Skip to content

Commit 4cd065d

Browse files
authored
feat(headless): supporting standard lifecycle events (#5632)
* refactor(headless): use `WaitStable` for `waitload` action Signed-off-by: Dwi Siswanto <[email protected]> * feat(headless): add `getNavigationFunc` Signed-off-by: Dwi Siswanto <[email protected]> * feat(headless): add `WaitDOM` action Signed-off-by: Dwi Siswanto <[email protected]> * feat(headless): add `WaitFMP` action Signed-off-by: Dwi Siswanto <[email protected]> * feat(headless): add `WaitFCP` action Signed-off-by: Dwi Siswanto <[email protected]> * feat(headless): add `WaitIdle` action Signed-off-by: Dwi Siswanto <[email protected]> * refactor(headless): `ActionWaitLoad` waits for `proto.PageLifecycleEventNameLoad` also rename `Page.WaitLoad` to `Page.WaitStable` method. Signed-off-by: Dwi Siswanto <[email protected]> * feat(headless): add `WaitStable` action Signed-off-by: Dwi Siswanto <[email protected]> * refactor(headless): supporting `duration` arg for `WaitStable` action Signed-off-by: Dwi Siswanto <[email protected]> * chore: ignore `*.png` Signed-off-by: Dwi Siswanto <[email protected]> * test(headless): update `TestActionScreenshot*` call `ActionWaitFMP` instead of `WaitLoad` before take screenshot Signed-off-by: Dwi Siswanto <[email protected]> * feat(headless): chained with `Timeout` when `WaitStable` Signed-off-by: Dwi Siswanto <[email protected]> --------- Signed-off-by: Dwi Siswanto <[email protected]>
1 parent 3d2f31a commit 4cd065d

File tree

4 files changed

+92
-15
lines changed

4 files changed

+92
-15
lines changed

.gitignore

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,4 +39,7 @@ dist
3939
pkg/protocols/common/helpers/deserialization/testdata/Deserialize.class
4040
pkg/protocols/common/helpers/deserialization/testdata/ValueObject.class
4141
pkg/protocols/common/helpers/deserialization/testdata/ValueObject2.ser
42-
vendor
42+
vendor
43+
44+
# Headless `screenshot` action
45+
*.png

pkg/protocols/headless/engine/action_types.go

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,24 @@ const (
4545
// ActionFilesInput performs an action on a file input.
4646
// name:files
4747
ActionFilesInput
48-
// ActionWaitLoad waits for the page to stop loading.
48+
// ActionWaitDOM waits for the HTML document has been completely loaded & parsed.
49+
// name:waitdom
50+
ActionWaitDOM
51+
// ActionWaitFCP waits for the first piece of content (text, image, etc.) is painted on the screen.
52+
// name:waitfcp
53+
ActionWaitFCP
54+
// ActionWaitFMP waits for page has rendered enough meaningful content to be useful to the user.
55+
// name:waitfmp
56+
ActionWaitFMP
57+
// ActionWaitIdle waits for the network is completely idle (no ongoing network requests).
58+
// name:waitidle
59+
ActionWaitIdle
60+
// ActionWaitLoad waits for the page and all its resources (like stylesheets and images) have finished loading.
4961
// name:waitload
5062
ActionWaitLoad
63+
// ActionWaitStable waits until the page is stable.
64+
// name:waitstable
65+
ActionWaitStable
5166
// ActionGetResource performs a get resource action on an element
5267
// name:getresource
5368
ActionGetResource
@@ -102,7 +117,12 @@ var ActionStringToAction = map[string]ActionType{
102117
"time": ActionTimeInput,
103118
"select": ActionSelectInput,
104119
"files": ActionFilesInput,
120+
"waitdom": ActionWaitDOM,
121+
"waitfcp": ActionWaitFCP,
122+
"waitfmp": ActionWaitFMP,
123+
"waitidle": ActionWaitIdle,
105124
"waitload": ActionWaitLoad,
125+
"waitstable": ActionWaitStable,
106126
"getresource": ActionGetResource,
107127
"extract": ActionExtract,
108128
"setmethod": ActionSetMethod,
@@ -129,7 +149,12 @@ var ActionToActionString = map[ActionType]string{
129149
ActionTimeInput: "time",
130150
ActionSelectInput: "select",
131151
ActionFilesInput: "files",
152+
ActionWaitDOM: "waitdom",
153+
ActionWaitFCP: "waitfcp",
154+
ActionWaitFMP: "waitfmp",
155+
ActionWaitIdle: "waitidle",
132156
ActionWaitLoad: "waitload",
157+
ActionWaitStable: "waitstable",
133158
ActionGetResource: "getresource",
134159
ActionExtract: "extract",
135160
ActionSetMethod: "setmethod",

pkg/protocols/headless/engine/page_actions.go

Lines changed: 60 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -94,8 +94,28 @@ func (p *Page) ExecuteActions(input *contextargs.Context, actions []*Action, var
9494
err = p.TimeInputElement(act, outData)
9595
case ActionSelectInput:
9696
err = p.SelectInputElement(act, outData)
97+
case ActionWaitDOM:
98+
event := proto.PageLifecycleEventNameDOMContentLoaded
99+
err = p.WaitPageLifecycleEvent(act, outData, event)
100+
case ActionWaitFCP:
101+
event := proto.PageLifecycleEventNameFirstContentfulPaint
102+
err = p.WaitPageLifecycleEvent(act, outData, event)
103+
case ActionWaitFMP:
104+
event := proto.PageLifecycleEventNameFirstMeaningfulPaint
105+
err = p.WaitPageLifecycleEvent(act, outData, event)
106+
case ActionWaitIdle:
107+
event := proto.PageLifecycleEventNameNetworkIdle
108+
err = p.WaitPageLifecycleEvent(act, outData, event)
97109
case ActionWaitLoad:
98-
err = p.WaitLoad(act, outData)
110+
event := proto.PageLifecycleEventNameLoad
111+
err = p.WaitPageLifecycleEvent(act, outData, event)
112+
case ActionWaitStable:
113+
err = p.WaitStable(act, outData)
114+
// NOTE(dwisiswant0): Mapping `ActionWaitLoad` to `Page.WaitStable`,
115+
// just in case waiting for the `proto.PageLifecycleEventNameLoad` event
116+
// doesn't meet expectations.
117+
// case ActionWaitLoad, ActionWaitStable:
118+
// err = p.WaitStable(act, outData)
99119
case ActionGetResource:
100120
err = p.GetResource(act, outData)
101121
case ActionExtract:
@@ -204,6 +224,17 @@ func createBackOffSleeper(pollTimeout, timeout time.Duration) utils.Sleeper {
204224
}
205225
}
206226

227+
func getNavigationFunc(p *Page, act *Action, event proto.PageLifecycleEventName) (func(), error) {
228+
dur, err := getTimeout(p, act)
229+
if err != nil {
230+
return nil, errors.Wrap(err, "Wrong timeout given")
231+
}
232+
233+
fn := p.page.Timeout(dur).WaitNavigation(event)
234+
235+
return fn, nil
236+
}
237+
207238
func getTimeout(p *Page, act *Action) (time.Duration, error) {
208239
return geTimeParameter(p, act, "timeout", 3, time.Second)
209240
}
@@ -518,20 +549,38 @@ func (p *Page) SelectInputElement(act *Action, out ActionData) error {
518549
return nil
519550
}
520551

521-
// WaitLoad waits for the page to load
522-
func (p *Page) WaitLoad(act *Action, out ActionData) error {
523-
p.page.Timeout(2 * time.Second).WaitNavigation(proto.PageLifecycleEventNameFirstMeaningfulPaint)()
524-
525-
// Wait for the window.onload event and also wait for the network requests
526-
// to become idle for a maximum duration of 3 seconds. If the requests
527-
// do not finish,
528-
if err := p.page.WaitLoad(); err != nil {
529-
return errors.Wrap(err, "could not wait load event")
552+
// WaitPageLifecycleEvent waits for specified page lifecycle event name
553+
func (p *Page) WaitPageLifecycleEvent(act *Action, out ActionData, event proto.PageLifecycleEventName) error {
554+
fn, err := getNavigationFunc(p, act, event)
555+
if err != nil {
556+
return err
530557
}
531-
_ = p.page.WaitIdle(1 * time.Second)
558+
559+
fn()
560+
532561
return nil
533562
}
534563

564+
// WaitStable waits until the page is stable
565+
func (p *Page) WaitStable(act *Action, out ActionData) error {
566+
var dur time.Duration = time.Second // default stable page duration: 1s
567+
568+
timeout, err := getTimeout(p, act)
569+
if err != nil {
570+
return errors.Wrap(err, "Wrong timeout given")
571+
}
572+
573+
argDur := act.Data["duration"]
574+
if argDur != "" {
575+
dur, err = time.ParseDuration(argDur)
576+
if err != nil {
577+
dur = time.Second
578+
}
579+
}
580+
581+
return p.page.Timeout(timeout).WaitStable(dur)
582+
}
583+
535584
// GetResource gets a resource from an element from page.
536585
func (p *Page) GetResource(act *Action, out ActionData) error {
537586
element, err := p.pageElementBy(act.Data)

pkg/protocols/headless/engine/page_actions_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,7 @@ func TestActionScreenshot(t *testing.T) {
201201
filePath := filepath.Join(os.TempDir(), "test.png")
202202
actions := []*Action{
203203
{ActionType: ActionTypeHolder{ActionType: ActionNavigate}, Data: map[string]string{"url": "{{BaseURL}}"}},
204-
{ActionType: ActionTypeHolder{ActionType: ActionWaitLoad}},
204+
{ActionType: ActionTypeHolder{ActionType: ActionWaitFMP}},
205205
{ActionType: ActionTypeHolder{ActionType: ActionScreenshot}, Data: map[string]string{"to": filePath}},
206206
}
207207

@@ -229,7 +229,7 @@ func TestActionScreenshotToDir(t *testing.T) {
229229

230230
actions := []*Action{
231231
{ActionType: ActionTypeHolder{ActionType: ActionNavigate}, Data: map[string]string{"url": "{{BaseURL}}"}},
232-
{ActionType: ActionTypeHolder{ActionType: ActionWaitLoad}},
232+
{ActionType: ActionTypeHolder{ActionType: ActionWaitFMP}},
233233
{ActionType: ActionTypeHolder{ActionType: ActionScreenshot}, Data: map[string]string{"to": filePath, "mkdir": "true"}},
234234
}
235235

0 commit comments

Comments
 (0)