Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Prepare Page for async migration part #3 #1352

Merged
merged 17 commits into from
May 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 26 additions & 26 deletions browser/mapping_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -319,38 +319,38 @@ type pageAPI interface {
InputValue(selector string, opts goja.Value) (string, error)
IsChecked(selector string, opts goja.Value) (bool, error)
IsClosed() bool
IsDisabled(selector string, opts goja.Value) bool
IsEditable(selector string, opts goja.Value) bool
IsEnabled(selector string, opts goja.Value) bool
IsHidden(selector string, opts goja.Value) bool
IsVisible(selector string, opts goja.Value) bool
IsDisabled(selector string, opts goja.Value) (bool, error)
IsEditable(selector string, opts goja.Value) (bool, error)
IsEnabled(selector string, opts goja.Value) (bool, error)
IsHidden(selector string, opts goja.Value) (bool, error)
IsVisible(selector string, opts goja.Value) (bool, error)
Locator(selector string, opts goja.Value) *common.Locator
MainFrame() *common.Frame
On(event string, handler func(*common.ConsoleMessage) error) error
Opener() pageAPI
Press(selector string, key string, opts goja.Value)
Press(selector string, key string, opts goja.Value) error
Query(selector string) (*common.ElementHandle, error)
QueryAll(selector string) ([]*common.ElementHandle, error)
Reload(opts goja.Value) *common.Response
Screenshot(opts goja.Value) goja.ArrayBuffer
SelectOption(selector string, values goja.Value, opts goja.Value) []string
SetContent(html string, opts goja.Value)
Screenshot(opts goja.Value) ([]byte, error)
SelectOption(selector string, values goja.Value, opts goja.Value) ([]string, error)
SetContent(html string, opts goja.Value) error
SetDefaultNavigationTimeout(timeout int64)
SetDefaultTimeout(timeout int64)
SetExtraHTTPHeaders(headers map[string]string)
SetInputFiles(selector string, files goja.Value, opts goja.Value)
SetExtraHTTPHeaders(headers map[string]string) error
SetInputFiles(selector string, files goja.Value, opts goja.Value) error
SetViewportSize(viewportSize goja.Value) error
Tap(selector string, opts goja.Value) error
TextContent(selector string, opts goja.Value) string
TextContent(selector string, opts goja.Value) (string, error)
ThrottleCPU(common.CPUProfile) error
ThrottleNetwork(common.NetworkProfile) error
Title() (string, error)
Type(selector string, text string, opts goja.Value)
Type(selector string, text string, opts goja.Value) error
Uncheck(selector string, opts goja.Value) error
URL() (string, error)
ViewportSize() map[string]float64
WaitForFunction(fn, opts goja.Value, args ...goja.Value) (any, error)
WaitForLoadState(state string, opts goja.Value)
WaitForLoadState(state string, opts goja.Value) error
WaitForNavigation(opts goja.Value) (*common.Response, error)
WaitForSelector(selector string, opts goja.Value) (*common.ElementHandle, error)
WaitForTimeout(timeout int64)
Expand All @@ -372,7 +372,7 @@ type frameAPI interface {
Click(selector string, opts goja.Value) error
Content() (string, error)
Dblclick(selector string, opts goja.Value) error
DispatchEvent(selector string, typ string, eventInit goja.Value, opts goja.Value)
DispatchEvent(selector string, typ string, eventInit goja.Value, opts goja.Value) error
// EvaluateWithContext for internal use only
EvaluateWithContext(ctx context.Context, pageFunc goja.Value, args ...goja.Value) (any, error)
Evaluate(pageFunc goja.Value, args ...goja.Value) (any, error)
Expand All @@ -388,11 +388,11 @@ type frameAPI interface {
InputValue(selector string, opts goja.Value) (string, error)
IsChecked(selector string, opts goja.Value) (bool, error)
IsDetached() bool
IsDisabled(selector string, opts goja.Value) bool
IsEditable(selector string, opts goja.Value) bool
IsEnabled(selector string, opts goja.Value) bool
IsHidden(selector string, opts goja.Value) bool
IsVisible(selector string, opts goja.Value) bool
IsDisabled(selector string, opts goja.Value) (bool, error)
IsEditable(selector string, opts goja.Value) (bool, error)
IsEnabled(selector string, opts goja.Value) (bool, error)
IsHidden(selector string, opts goja.Value) (bool, error)
IsVisible(selector string, opts goja.Value) (bool, error)
ID() string
LoaderID() string
Locator(selector string, opts goja.Value) *common.Locator
Expand All @@ -401,18 +401,18 @@ type frameAPI interface {
QueryAll(selector string) ([]*common.ElementHandle, error)
Page() *common.Page
ParentFrame() *common.Frame
Press(selector string, key string, opts goja.Value)
SelectOption(selector string, values goja.Value, opts goja.Value) []string
SetContent(html string, opts goja.Value)
Press(selector string, key string, opts goja.Value) error
SelectOption(selector string, values goja.Value, opts goja.Value) ([]string, error)
SetContent(html string, opts goja.Value) error
SetInputFiles(selector string, files goja.Value, opts goja.Value)
Tap(selector string, opts goja.Value) error
TextContent(selector string, opts goja.Value) string
TextContent(selector string, opts goja.Value) (string, error)
Title() string
Type(selector string, text string, opts goja.Value)
Type(selector string, text string, opts goja.Value) error
Uncheck(selector string, opts goja.Value) error
URL() string
WaitForFunction(pageFunc, opts goja.Value, args ...goja.Value) (any, error)
WaitForLoadState(state string, opts goja.Value)
WaitForLoadState(state string, opts goja.Value) error
WaitForNavigation(opts goja.Value) (*common.Response, error)
WaitForSelector(selector string, opts goja.Value) (*common.ElementHandle, error)
WaitForTimeout(timeout int64)
Expand Down
4 changes: 1 addition & 3 deletions browser/page_mapping.go
Original file line number Diff line number Diff line change
Expand Up @@ -142,10 +142,8 @@ func mapPage(vu moduleVU, p *common.Page) mapping { //nolint:gocognit,cyclop
return rt.ToValue(r).ToObject(rt), nil
},
"screenshot": func(opts goja.Value) (*goja.ArrayBuffer, error) {
ctx := vu.Context()

popts := common.NewPageScreenshotOptions()
if err := popts.Parse(ctx, opts); err != nil {
if err := popts.Parse(vu.Context(), opts); err != nil {
return nil, fmt.Errorf("parsing page screenshot options: %w", err)
}

Expand Down
97 changes: 52 additions & 45 deletions common/frame.go
Original file line number Diff line number Diff line change
Expand Up @@ -1175,19 +1175,19 @@ func (f *Frame) setDetached(detached bool) {

// IsEditable returns true if the first element that matches the selector
// is editable. Otherwise, returns false.
func (f *Frame) IsEditable(selector string, opts goja.Value) bool {
func (f *Frame) IsEditable(selector string, opts goja.Value) (bool, error) {
f.log.Debugf("Frame:IsEditable", "fid:%s furl:%q sel:%q", f.ID(), f.URL(), selector)

popts := NewFrameIsEditableOptions(f.defaultTimeout())
if err := popts.Parse(f.ctx, opts); err != nil {
k6ext.Panic(f.ctx, "%w", err)
return false, fmt.Errorf("parsing is editable options: %w", err)
}
editable, err := f.isEditable(selector, popts)
if err != nil {
k6ext.Panic(f.ctx, "checking is %q editable: %w", selector, err)
return false, fmt.Errorf("checking is %q editable: %w", selector, err)
}

return editable
return editable, nil
}

func (f *Frame) isEditable(selector string, opts *FrameIsEditableOptions) (bool, error) {
Expand Down Expand Up @@ -1216,19 +1216,19 @@ func (f *Frame) isEditable(selector string, opts *FrameIsEditableOptions) (bool,

// IsEnabled returns true if the first element that matches the selector
// is enabled. Otherwise, returns false.
func (f *Frame) IsEnabled(selector string, opts goja.Value) bool {
func (f *Frame) IsEnabled(selector string, opts goja.Value) (bool, error) {
f.log.Debugf("Frame:IsEnabled", "fid:%s furl:%q sel:%q", f.ID(), f.URL(), selector)

popts := NewFrameIsEnabledOptions(f.defaultTimeout())
if err := popts.Parse(f.ctx, opts); err != nil {
k6ext.Panic(f.ctx, "parsing is enabled options: %w", err)
return false, fmt.Errorf("parsing is enabled options: %w", err)
}
enabled, err := f.isEnabled(selector, popts)
if err != nil {
k6ext.Panic(f.ctx, "checking is %q enabled: %w", selector, err)
return false, fmt.Errorf("checking is %q enabled: %w", selector, err)
}

return enabled
return enabled, nil
}

func (f *Frame) isEnabled(selector string, opts *FrameIsEnabledOptions) (bool, error) {
Expand Down Expand Up @@ -1257,19 +1257,19 @@ func (f *Frame) isEnabled(selector string, opts *FrameIsEnabledOptions) (bool, e

// IsDisabled returns true if the first element that matches the selector
// is disabled. Otherwise, returns false.
func (f *Frame) IsDisabled(selector string, opts goja.Value) bool {
func (f *Frame) IsDisabled(selector string, opts goja.Value) (bool, error) {
f.log.Debugf("Frame:IsDisabled", "fid:%s furl:%q sel:%q", f.ID(), f.URL(), selector)

popts := NewFrameIsDisabledOptions(f.defaultTimeout())
if err := popts.Parse(f.ctx, opts); err != nil {
k6ext.Panic(f.ctx, "parsing is disabled options: %w", err)
return false, fmt.Errorf("parsing is disabled options: %w", err)
}
disabled, err := f.isDisabled(selector, popts)
if err != nil {
k6ext.Panic(f.ctx, "checking is %q disabled: %w", selector, err)
return false, fmt.Errorf("checking is %q disabled: %w", selector, err)
}

return disabled
return disabled, nil
}

func (f *Frame) isDisabled(selector string, opts *FrameIsDisabledOptions) (bool, error) {
Expand Down Expand Up @@ -1427,18 +1427,20 @@ func (f *Frame) ParentFrame() *Frame {
}

// Press presses the given key for the first element found that matches the selector.
func (f *Frame) Press(selector, key string, opts goja.Value) {
func (f *Frame) Press(selector, key string, opts goja.Value) error {
f.log.Debugf("Frame:Press", "fid:%s furl:%q sel:%q key:%q", f.ID(), f.URL(), selector, key)

popts := NewFramePressOptions(f.defaultTimeout())
if err := popts.Parse(f.ctx, opts); err != nil {
k6ext.Panic(f.ctx, "parsing press options: %w", err)
return fmt.Errorf("parsing press options: %w", err)
}
if err := f.press(selector, key, popts); err != nil {
k6ext.Panic(f.ctx, "pressing %q on %q: %w", key, selector, err)
return fmt.Errorf("pressing %q on %q: %w", key, selector, err)
}

applySlowMo(f.ctx)

return nil
}

func (f *Frame) press(selector, key string, opts *FramePressOptions) error {
Expand All @@ -1458,21 +1460,21 @@ func (f *Frame) press(selector, key string, opts *FramePressOptions) error {

// SelectOption selects the given options and returns the array of
// option values of the first element found that matches the selector.
func (f *Frame) SelectOption(selector string, values goja.Value, opts goja.Value) []string {
func (f *Frame) SelectOption(selector string, values goja.Value, opts goja.Value) ([]string, error) {
f.log.Debugf("Frame:SelectOption", "fid:%s furl:%q sel:%q", f.ID(), f.URL(), selector)

popts := NewFrameSelectOptionOptions(f.defaultTimeout())
if err := popts.Parse(f.ctx, opts); err != nil {
k6ext.Panic(f.ctx, "parsing select option options: %w", err)
return nil, fmt.Errorf("parsing select option options: %w", err)
}
v, err := f.selectOption(selector, values, popts)
if err != nil {
k6ext.Panic(f.ctx, "selecting option on %q: %w", selector, err)
return nil, fmt.Errorf("selecting option on %q: %w", selector, err)
}

applySlowMo(f.ctx)

return v
return v, nil
}

func (f *Frame) selectOption(selector string, values goja.Value, opts *FrameSelectOptionOptions) ([]string, error) {
Expand Down Expand Up @@ -1516,14 +1518,14 @@ func (f *Frame) selectOption(selector string, values goja.Value, opts *FrameSele
}

// SetContent replaces the entire HTML document content.
func (f *Frame) SetContent(html string, opts goja.Value) {
func (f *Frame) SetContent(html string, opts goja.Value) error {
f.log.Debugf("Frame:SetContent", "fid:%s furl:%q", f.ID(), f.URL())

parsedOpts := NewFrameSetContentOptions(
f.manager.timeoutSettings.navigationTimeout(),
)
if err := parsedOpts.Parse(f.ctx, opts); err != nil {
k6ext.Panic(f.ctx, "parsing set content options: %w", err)
return fmt.Errorf("parsing set content options: %w", err)
}

js := `(html) => {
Expand All @@ -1540,10 +1542,12 @@ func (f *Frame) SetContent(html string, opts goja.Value) {
returnByValue: true,
}
if _, err := f.evaluate(f.ctx, utilityWorld, eopts, js, html); err != nil {
k6ext.Panic(f.ctx, "setting content: %w", err)
return fmt.Errorf("setting content: %w", err)
}

applySlowMo(f.ctx)

return nil
}

// SetInputFiles sets input files for the selected element.
Expand Down Expand Up @@ -1615,21 +1619,19 @@ func (f *Frame) setInputFiles(selector string, files *Files, opts *FrameSetInput

// TextContent returns the textContent attribute of the first element found
// that matches the selector.
func (f *Frame) TextContent(selector string, opts goja.Value) string {
func (f *Frame) TextContent(selector string, opts goja.Value) (string, error) {
f.log.Debugf("Frame:TextContent", "fid:%s furl:%q sel:%q", f.ID(), f.URL(), selector)

popts := NewFrameTextContentOptions(f.defaultTimeout())
if err := popts.Parse(f.ctx, opts); err != nil {
k6ext.Panic(f.ctx, "parsing text content options: %w", err)
return "", fmt.Errorf("parsing text content options: %w", err)
}
v, err := f.textContent(selector, popts)
if err != nil {
k6ext.Panic(f.ctx, "getting text content of %q: %w", selector, err)
return "", fmt.Errorf("getting text content of %q: %w", selector, err)
}

applySlowMo(f.ctx)

return v
return v, nil
}

func (f *Frame) textContent(selector string, opts *FrameTextContentOptions) (string, error) {
Expand Down Expand Up @@ -1674,18 +1676,20 @@ func (f *Frame) Title() string {
}

// Type text on the first element found matches the selector.
func (f *Frame) Type(selector, text string, opts goja.Value) {
func (f *Frame) Type(selector, text string, opts goja.Value) error {
f.log.Debugf("Frame:Type", "fid:%s furl:%q sel:%q text:%q", f.ID(), f.URL(), selector, text)

popts := NewFrameTypeOptions(f.defaultTimeout())
if err := popts.Parse(f.ctx, opts); err != nil {
k6ext.Panic(f.ctx, "parsing type options: %w", err)
return fmt.Errorf("parsing type options: %w", err)
}
if err := f.typ(selector, text, popts); err != nil {
k6ext.Panic(f.ctx, "typing %q in %q: %w", text, selector, err)
return fmt.Errorf("typing %q in %q: %w", text, selector, err)
}

applySlowMo(f.ctx)

return nil
}

func (f *Frame) typ(selector, text string, opts *FrameTypeOptions) error {
Expand Down Expand Up @@ -1805,45 +1809,48 @@ func (f *Frame) waitForFunction(

// WaitForLoadState waits for the given load state to be reached.
// This will unblock if that lifecycle event has already been received.
func (f *Frame) WaitForLoadState(state string, opts goja.Value) {
func (f *Frame) WaitForLoadState(state string, opts goja.Value) error {
f.log.Debugf("Frame:WaitForLoadState", "fid:%s furl:%q state:%s", f.ID(), f.URL(), state)
defer f.log.Debugf("Frame:WaitForLoadState:return", "fid:%s furl:%q state:%s", f.ID(), f.URL(), state)

parsedOpts := NewFrameWaitForLoadStateOptions(f.defaultTimeout())
err := parsedOpts.Parse(f.ctx, opts)
if err != nil {
k6ext.Panic(f.ctx, "parsing waitForLoadState %q options: %v", state, err)
waitForLoadStateOpts := NewFrameWaitForLoadStateOptions(f.defaultTimeout())
if err := waitForLoadStateOpts.Parse(f.ctx, opts); err != nil {
return fmt.Errorf("parsing waitForLoadState %q options: %w", state, err)
}

timeoutCtx, timeoutCancel := context.WithTimeout(f.ctx, parsedOpts.Timeout)
timeoutCtx, timeoutCancel := context.WithTimeout(f.ctx, waitForLoadStateOpts.Timeout)
defer timeoutCancel()

waitUntil := LifecycleEventLoad
if state != "" {
if err = waitUntil.UnmarshalText([]byte(state)); err != nil {
k6ext.Panic(f.ctx, "waiting for load state: %v", err)
if err := waitUntil.UnmarshalText([]byte(state)); err != nil {
return fmt.Errorf("unmarshaling wait for load state %q: %w", state, err)
}
}

lifecycleEvtCh, lifecycleEvtCancel := createWaitForEventPredicateHandler(
timeoutCtx, f, []string{EventFrameAddLifecycle},
lifecycleEvent, lifecycleEventCancel := createWaitForEventPredicateHandler(
timeoutCtx,
f,
[]string{EventFrameAddLifecycle},
func(data any) bool {
if le, ok := data.(FrameLifecycleEvent); ok {
return le.Event == waitUntil
}
return false
})
defer lifecycleEvtCancel()
defer lifecycleEventCancel()

if f.hasLifecycleEventFired(waitUntil) {
return
return nil
}

select {
case <-lifecycleEvtCh:
case <-lifecycleEvent:
case <-timeoutCtx.Done():
k6ext.Panic(f.ctx, "waiting for load state %q: %v", state, err)
return fmt.Errorf("waiting for load state %q: %w", state, timeoutCtx.Err())
}

return nil
}

// WaitForNavigation waits for the given navigation lifecycle event to happen.
Expand Down
Loading
Loading