@@ -28,6 +28,7 @@ import (
28
28
"github.com/chromedp/cdproto/cdp"
29
29
"github.com/chromedp/cdproto/dom"
30
30
"github.com/chromedp/cdproto/runtime"
31
+ "github.com/chromedp/cdproto/target"
31
32
"github.com/dop251/goja"
32
33
"github.com/grafana/xk6-browser/api"
33
34
k6common "go.k6.io/k6/js/common"
@@ -52,6 +53,21 @@ func NewExecutionContext(
52
53
ctx context.Context , session * Session , frame * Frame ,
53
54
id runtime.ExecutionContextID , logger * Logger ,
54
55
) * ExecutionContext {
56
+ var (
57
+ sid target.SessionID
58
+ fid cdp.FrameID
59
+ furl string
60
+ )
61
+ if session != nil {
62
+ sid = session .id
63
+ }
64
+ if frame != nil {
65
+ fid = frame .id
66
+ furl = frame .url
67
+ }
68
+ logger .Debugf ("NewExecutionContext" , "sid:%s fid:%s ecid:%d furl:%q" ,
69
+ sid , fid , id , furl )
70
+
55
71
return & ExecutionContext {
56
72
ctx : ctx ,
57
73
session : session ,
@@ -64,21 +80,31 @@ func NewExecutionContext(
64
80
65
81
// Adopts specified backend node into this execution context from another execution context
66
82
func (e * ExecutionContext ) adoptBackendNodeId (backendNodeID cdp.BackendNodeID ) (* ElementHandle , error ) {
67
- var remoteObj * runtime.RemoteObject
68
- var err error
83
+ e .logger .Debugf ("ExecutionContext:adoptBackendNodeId" , "sid:%s tid:%s fid:%s ecid:%d furl:%q bnid:%d" ,
84
+ e .session .id , e .session .targetID , e .frame .id , e .id , e .frame .url , backendNodeID )
85
+
86
+ var (
87
+ remoteObj * runtime.RemoteObject
88
+ err error
89
+ )
69
90
70
91
action := dom .ResolveNode ().
71
92
WithBackendNodeID (backendNodeID ).
72
93
WithExecutionContextID (e .id )
94
+
73
95
if remoteObj , err = action .Do (cdp .WithExecutor (e .ctx , e .session )); err != nil {
74
- return nil , fmt .Errorf ("unable to get DOM node: %w" , err )
96
+ return nil , fmt .Errorf ("cannot resolve dom node: %w" , err )
75
97
}
76
98
77
99
return NewJSHandle (e .ctx , e .session , e , e .frame , remoteObj , e .logger ).AsElement ().(* ElementHandle ), nil
78
100
}
79
101
80
102
// Adopts the specified element handle into this execution context from another execution context
81
103
func (e * ExecutionContext ) adoptElementHandle (elementHandle * ElementHandle ) (* ElementHandle , error ) {
104
+ e .logger .Debugf ("ExecutionContext:adoptElementHandle" , "sid:%s tid:%s fid:%s ecid:%d furl:%q ehfid:%s ehsid:%s" ,
105
+ e .session .id , e .session .targetID , e .frame .id , e .id , e .frame .url ,
106
+ elementHandle .frame .id , elementHandle .session .id )
107
+
82
108
if elementHandle .execCtx == e {
83
109
panic ("Cannot adopt handle that already belongs to this execution context" )
84
110
}
@@ -91,95 +117,108 @@ func (e *ExecutionContext) adoptElementHandle(elementHandle *ElementHandle) (*El
91
117
92
118
action := dom .DescribeNode ().WithObjectID (elementHandle .remoteObject .ObjectID )
93
119
if node , err = action .Do (cdp .WithExecutor (e .ctx , e .session )); err != nil {
94
- return nil , fmt .Errorf ("unable to get DOM node: %w" , err )
120
+ return nil , fmt .Errorf ("cannot describe dom node: %w" , err )
95
121
}
96
122
97
123
return e .adoptBackendNodeId (node .BackendNodeID )
98
124
}
99
125
100
126
// evaluate will evaluate provided callable within this execution context and return by value or handle
101
127
func (e * ExecutionContext ) evaluate (apiCtx context.Context , forceCallable bool , returnByValue bool , pageFunc goja.Value , args ... goja.Value ) (res interface {}, err error ) {
128
+ e .logger .Debugf ("ExecutionContext:evaluate" , "sid:%s tid:%s fid:%s ecid:%d furl:%q" ,
129
+ e .session .id , e .session .targetID , e .frame .id , e .id , e .frame .url )
130
+
102
131
suffix := `//# sourceURL=` + evaluationScriptURL
103
132
104
- isCallable := forceCallable
133
+ var (
134
+ isCallable = forceCallable
135
+ expression = pageFunc .ToString ().String ()
136
+ )
105
137
if ! forceCallable {
106
- _ , isCallable = goja .AssertFunction (pageFunc .(goja. Value ) )
138
+ _ , isCallable = goja .AssertFunction (pageFunc )
107
139
}
108
-
109
140
if ! isCallable {
110
- expression := pageFunc .ToString ().String ()
111
141
expressionWithSourceURL := expression
112
142
if ! sourceURLRegex .Match ([]byte (expression )) {
113
143
expressionWithSourceURL = expression + "\n " + suffix
114
144
}
115
145
116
- var remoteObject * runtime.RemoteObject
117
- var exceptionDetails * runtime.ExceptionDetails
146
+ var (
147
+ remoteObject * runtime.RemoteObject
148
+ exceptionDetails * runtime.ExceptionDetails
149
+ )
118
150
action := runtime .Evaluate (expressionWithSourceURL ).
119
151
WithContextID (e .id ).
120
152
WithReturnByValue (returnByValue ).
121
153
WithAwaitPromise (true ).
122
154
WithUserGesture (true )
123
155
if remoteObject , exceptionDetails , err = action .Do (cdp .WithExecutor (apiCtx , e .session )); err != nil {
124
- return nil , fmt .Errorf ("unable to evaluate expression: %w" , err )
156
+ return nil , fmt .Errorf ("cannot evaluate expression (%s) : %w" , expressionWithSourceURL , exceptionDetails )
125
157
}
126
158
if exceptionDetails != nil {
127
- return nil , fmt .Errorf ("unable to evaluate expression: %w" , exceptionDetails )
159
+ return nil , fmt .Errorf ("cannot evaluate expression (%s) : %w" , expressionWithSourceURL , exceptionDetails )
128
160
}
129
- if remoteObject != nil {
130
- if returnByValue {
131
- res , err = valueFromRemoteObject (apiCtx , remoteObject )
132
- if err != nil {
133
- return nil , fmt .Errorf ("unable to extract value from remote object: %w" , err )
134
- }
135
- } else if remoteObject .ObjectID != "" {
136
- // Note: we don't use the passed in apiCtx here as it could be tied to a timeout
137
- res = NewJSHandle (e .ctx , e .session , e , e .frame , remoteObject , e .logger )
161
+ if remoteObject == nil {
162
+ return
163
+ }
164
+ if returnByValue {
165
+ res , err = valueFromRemoteObject (apiCtx , remoteObject )
166
+ if err != nil {
167
+ return nil , fmt .Errorf ("cannot extract value from remote object (%s): %w" , remoteObject .ObjectID , err )
138
168
}
169
+ } else if remoteObject .ObjectID != "" {
170
+ // Note: we don't use the passed in apiCtx here as it could be tied to a timeout
171
+ res = NewJSHandle (e .ctx , e .session , e , e .frame , remoteObject , e .logger )
139
172
}
140
173
} else {
141
- functionText := pageFunc .ToString ().String ()
142
174
var arguments []* runtime.CallArgument
143
175
for _ , arg := range args {
144
176
result , err := convertArgument (apiCtx , e , arg )
145
177
if err != nil {
146
- return nil , fmt .Errorf ("unable to convert argument: %w" , err )
178
+ return nil , fmt .Errorf ("cannot convert argument (%q) : %w" , arg , err )
147
179
}
148
180
arguments = append (arguments , result )
149
181
}
150
182
151
- var remoteObject * runtime.RemoteObject
152
- var exceptionDetails * runtime.ExceptionDetails
153
- action := runtime .CallFunctionOn (functionText + "\n " + suffix + "\n " ).
183
+ var (
184
+ remoteObject * runtime.RemoteObject
185
+ exceptionDetails * runtime.ExceptionDetails
186
+ functionOn = expression + "\n " + suffix + "\n "
187
+ )
188
+ action := runtime .CallFunctionOn (functionOn ).
154
189
WithArguments (arguments ).
155
190
WithExecutionContextID (e .id ).
156
191
WithReturnByValue (returnByValue ).
157
192
WithAwaitPromise (true ).
158
193
WithUserGesture (true )
159
194
if remoteObject , exceptionDetails , err = action .Do (cdp .WithExecutor (apiCtx , e .session )); err != nil {
160
- return nil , fmt .Errorf ("unable to evaluate expression: %w" , err )
195
+ return nil , fmt .Errorf ("cannot call function on expression (%q) in execution context (%d) : %w" , functionOn , e . id , err )
161
196
}
162
197
if exceptionDetails != nil {
163
- return nil , fmt .Errorf ("unable to evaluate expression: %w" , exceptionDetails )
198
+ return nil , fmt .Errorf ("cannot call function on expression (%q) in execution context (%d) : %w" , functionOn , e . id , err )
164
199
}
165
- if remoteObject != nil {
166
- if returnByValue {
167
- res , err = valueFromRemoteObject (apiCtx , remoteObject )
168
- if err != nil {
169
- return nil , fmt .Errorf ("unable to extract value from remote object: %w" , err )
170
- }
171
- } else if remoteObject .ObjectID != "" {
172
- // Note: we don't use the passed in apiCtx here as it could be tied to a timeout
173
- res = NewJSHandle (e .ctx , e .session , e , e .frame , remoteObject , e .logger )
200
+ if remoteObject == nil {
201
+ return
202
+ }
203
+ if returnByValue {
204
+ res , err = valueFromRemoteObject (apiCtx , remoteObject )
205
+ if err != nil {
206
+ return nil , fmt .Errorf ("cannot extract value from remote object (%s): %w" , remoteObject .ObjectID , err )
174
207
}
208
+ } else if remoteObject .ObjectID != "" {
209
+ // Note: we don't use the passed in apiCtx here as it could be tied to a timeout
210
+ res = NewJSHandle (e .ctx , e .session , e , e .frame , remoteObject , e .logger )
175
211
}
176
212
}
177
213
178
- return res , err
214
+ return res , nil
179
215
}
180
216
181
217
// getInjectedScript returns a JS handle to the injected script of helper functions
182
218
func (e * ExecutionContext ) getInjectedScript (apiCtx context.Context ) (api.JSHandle , error ) {
219
+ e .logger .Debugf ("ExecutionContext:getInjectedScript" , "sid:%s tid:%s fid:%s ecid:%d furl:%q" ,
220
+ e .session .id , e .session .targetID , e .frame .id , e .id , e .frame .url )
221
+
183
222
if e .injectedScript == nil {
184
223
rt := k6common .GetRuntime (e .ctx )
185
224
suffix := `//# sourceURL=` + evaluationScriptURL
@@ -192,7 +231,7 @@ func (e *ExecutionContext) getInjectedScript(apiCtx context.Context) (api.JSHand
192
231
193
232
handle , err := e .evaluate (apiCtx , false , false , rt .ToValue (expressionWithSourceURL ))
194
233
if handle == nil || err != nil {
195
- return nil , err
234
+ return nil , fmt . Errorf ( "cannot get injected script (%q): %w" , suffix , err )
196
235
}
197
236
e .injectedScript = handle .(api.JSHandle )
198
237
}
0 commit comments