How to use EvaluateExpressionInternalAsync method of PuppeteerSharp.ExecutionContext class

Best Puppeteer-sharp code snippet using PuppeteerSharp.ExecutionContext.EvaluateExpressionInternalAsync

Run Puppeteer-sharp automation tests on LambdaTest cloud grid

Perform automation testing on 3000+ real desktop and mobile devices online.

ExecutionContext.cs

Source: ExecutionContext.cs Github

copy
1using Newtonsoft.Json.Linq;
2using PuppeteerSharp.Helpers;
3using PuppeteerSharp.Messaging;
4using System.Collections.Generic;
5using System.Linq;
6using System.Numerics;
7using System.Text.RegularExpressions;
8using System.Threading.Tasks;
9
10namespace PuppeteerSharp
11{
12    /// <summary>
13    /// The class represents a context for JavaScript execution. Examples of JavaScript contexts are:
14    /// Each <see cref="Frame"/> has a separate <see cref="ExecutionContext"/>
15    /// All kind of web workers have their own contexts
16    /// </summary>
17    public class ExecutionContext
18    {
19        internal const string EvaluationScriptUrl = "__puppeteer_evaluation_script__";
20
21        private readonly string _evaluationScriptSuffix = $"//# sourceURL={EvaluationScriptUrl}";
22        private static readonly Regex _sourceUrlRegex = new Regex(@"^[\040\t]*\/\/[@#] sourceURL=\s*(\S*?)\s*$", RegexOptions.Multiline);
23        private readonly CDPSession _client;
24        private readonly int _contextId;
25
26        internal DOMWorld World { get; }
27
28        internal ExecutionContext(
29            CDPSession client,
30            ContextPayload contextPayload,
31            DOMWorld world)
32        {
33            _client = client;
34            _contextId = contextPayload.Id;
35            World = world;
36        }
37
38        /// <summary>
39        /// Frame associated with this execution context.
40        /// </summary>
41        /// <remarks>
42        /// NOTE Not every execution context is associated with a frame. For example, workers and extensions have execution contexts that are not associated with frames.
43        /// </remarks>
44        public Frame Frame => World?.Frame;
45
46        /// <summary>
47        /// Executes a script in browser context
48        /// </summary>
49        /// <param name="script">Script to be evaluated in browser context</param>
50        /// <remarks>
51        /// If the script, returns a Promise, then the method would wait for the promise to resolve and return its value.
52        /// </remarks>
53        /// <seealso cref="EvaluateFunctionAsync{T}(string, object[])"/>
54        /// <seealso cref="EvaluateExpressionHandleAsync(string)"/>
55        /// <returns>Task which resolves to script return value</returns>
56        public Task<JToken> EvaluateExpressionAsync(string script) => EvaluateExpressionAsync<JToken>(script);
57
58        /// <summary>
59        /// Executes a script in browser context
60        /// </summary>
61        /// <typeparam name="T">The type to deserialize the result to</typeparam>
62        /// <param name="script">Script to be evaluated in browser context</param>
63        /// <remarks>
64        /// If the script, returns a Promise, then the method would wait for the promise to resolve and return its value.
65        /// </remarks>
66        /// <seealso cref="EvaluateFunctionAsync{T}(string, object[])"/>
67        /// <seealso cref="EvaluateExpressionHandleAsync(string)"/>
68        /// <returns>Task which resolves to script return value</returns>
69        public Task<T> EvaluateExpressionAsync<T>(string script)
70            => RemoteObjectTaskToObject<T>(EvaluateExpressionInternalAsync(true, script));
71
72        internal async Task<JSHandle> EvaluateExpressionHandleAsync(string script)
73            => CreateJSHandle(await EvaluateExpressionInternalAsync(false, script).ConfigureAwait(false));
74
75        /// <summary>
76        /// Executes a function in browser context
77        /// </summary>
78        /// <param name="script">Script to be evaluated in browser context</param>
79        /// <param name="args">Arguments to pass to script</param>
80        /// <remarks>
81        /// If the script, returns a Promise, then the method would wait for the promise to resolve and return its value.
82        /// <see cref="JSHandle"/> instances can be passed as arguments
83        /// </remarks>
84        /// <seealso cref="EvaluateExpressionAsync{T}(string)"/>
85        /// <returns>Task which resolves to script return value</returns>
86        public Task<JToken> EvaluateFunctionAsync(string script, params object[] args) => EvaluateFunctionAsync<JToken>(script, args);
87
88        /// <summary>
89        /// Executes a function in browser context
90        /// </summary>
91        /// <typeparam name="T">The type to deserialize the result to</typeparam>
92        /// <param name="script">Script to be evaluated in browser context</param>
93        /// <param name="args">Arguments to pass to script</param>
94        /// <remarks>
95        /// If the script, returns a Promise, then the method would wait for the promise to resolve and return its value.
96        /// <see cref="JSHandle"/> instances can be passed as arguments
97        /// </remarks>
98        /// <seealso cref="EvaluateExpressionAsync{T}(string)"/>
99        /// <returns>Task which resolves to script return value</returns>
100        public Task<T> EvaluateFunctionAsync<T>(string script, params object[] args)
101            => RemoteObjectTaskToObject<T>(EvaluateFunctionInternalAsync(true, script, args));
102
103        internal async Task<JSHandle> EvaluateFunctionHandleAsync(string script, params object[] args)
104            => CreateJSHandle(await EvaluateFunctionInternalAsync(false, script, args).ConfigureAwait(false));
105
106        /// <summary>
107        /// The method iterates JavaScript heap and finds all the objects with the given prototype.
108        /// </summary>
109        /// <returns>A task which resolves to a handle to an array of objects with this prototype.</returns>
110        /// <param name="prototypeHandle">A handle to the object prototype.</param>
111        public async Task<JSHandle> QueryObjectsAsync(JSHandle prototypeHandle)
112        {
113            if (prototypeHandle.Disposed)
114            {
115                throw new PuppeteerException("Prototype JSHandle is disposed!");
116            }
117
118            if (prototypeHandle.RemoteObject.ObjectId == null)
119            {
120                throw new PuppeteerException("Prototype JSHandle must not be referencing primitive value");
121            }
122
123            var response = await _client.SendAsync<RuntimeQueryObjectsResponse>("Runtime.queryObjects", new RuntimeQueryObjectsRequest
124            {
125                PrototypeObjectId = prototypeHandle.RemoteObject.ObjectId
126            }).ConfigureAwait(false);
127
128            return CreateJSHandle(response.Objects);
129        }
130
131        private async Task<T> RemoteObjectTaskToObject<T>(Task<RemoteObject> remote)
132        {
133            var response = await remote.ConfigureAwait(false);
134            return response == null ? default : (T)RemoteObjectHelper.ValueFromRemoteObject<T>(response);
135        }
136
137        private Task<RemoteObject> EvaluateExpressionInternalAsync(bool returnByValue, string script)
138            => ExecuteEvaluationAsync("Runtime.evaluate", new Dictionary<string, object>
139            {
140                ["expression"] = _sourceUrlRegex.IsMatch(script) ? script : $"{script}\n{_evaluationScriptSuffix}",
141                ["contextId"] = _contextId,
142                ["returnByValue"] = returnByValue,
143                ["awaitPromise"] = true,
144                ["userGesture"] = true
145            });
146
147        private Task<RemoteObject> EvaluateFunctionInternalAsync(bool returnByValue, string script, params object[] args)
148            => ExecuteEvaluationAsync("Runtime.callFunctionOn", new RuntimeCallFunctionOnRequest
149            {
150                FunctionDeclaration = $"{script}\n{_evaluationScriptSuffix}\n",
151                ExecutionContextId = _contextId,
152                Arguments = args.Select(FormatArgument),
153                ReturnByValue = returnByValue,
154                AwaitPromise = true,
155                UserGesture = true
156            });
157
158        private async Task<RemoteObject> ExecuteEvaluationAsync(string method, object args)
159        {
160            try
161            {
162                var response = await _client.SendAsync<EvaluateHandleResponse>(method, args).ConfigureAwait(false);
163
164                if (response.ExceptionDetails != null)
165                {
166                    throw new EvaluationFailedException("Evaluation failed: " +
167                        GetExceptionMessage(response.ExceptionDetails));
168                }
169
170                return response.Result;
171            }
172            catch (MessageException ex)
173            {
174                if (ex.Message.Contains("Object reference chain is too long") ||
175                    ex.Message.Contains("Object couldn't be returned by value"))
176                {
177                    return default;
178                }
179                throw new EvaluationFailedException(ex.Message, ex);
180            }
181        }
182
183        internal JSHandle CreateJSHandle(RemoteObject remoteObject)
184            => remoteObject.Subtype == RemoteObjectSubtype.Node && Frame != null
185                ? new ElementHandle(this, _client, remoteObject)
186                : new JSHandle(this, _client, remoteObject);
187
188        private object FormatArgument(object arg)
189        {
190            switch (arg)
191            {
192                case BigInteger big:
193                    return new { unserializableValue = $"{big}n" };
194
195                case int integer when integer == -0:
196                    return new { unserializableValue = "-0" };
197
198                case double d:
199                    if (double.IsPositiveInfinity(d))
200                    {
201                        return new { unserializableValue = "Infinity" };
202                    }
203
204                    if (double.IsNegativeInfinity(d))
205                    {
206                        return new { unserializableValue = "-Infinity" };
207                    }
208
209                    if (double.IsNaN(d))
210                    {
211                        return new { unserializableValue = "NaN" };
212                    }
213
214                    break;
215
216                case JSHandle objectHandle:
217                    return objectHandle.FormatArgument(this);
218            }
219            return new RuntimeCallFunctionOnRequestArgument
220            {
221                Value = arg
222            };
223        }
224
225        private static string GetExceptionMessage(EvaluateExceptionResponseDetails exceptionDetails)
226        {
227            if (exceptionDetails.Exception != null)
228            {
229                return exceptionDetails.Exception.Description ?? exceptionDetails.Exception.Value;
230            }
231            var message = exceptionDetails.Text;
232            if (exceptionDetails.StackTrace != null)
233            {
234                foreach (var callframe in exceptionDetails.StackTrace.CallFrames)
235                {
236                    var location = $"{callframe.Url}:{callframe.LineNumber}:{callframe.ColumnNumber}";
237                    var functionName = string.IsNullOrEmpty(callframe.FunctionName) ? "<anonymous>" : callframe.FunctionName;
238                    message += $"\n at ${functionName} (${location})";
239                }
240            }
241            return message;
242        }
243
244        internal async Task<ElementHandle> AdoptElementHandleASync(ElementHandle elementHandle)
245        {
246            if (elementHandle.ExecutionContext == this)
247            {
248                throw new PuppeteerException("Cannot adopt handle that already belongs to this execution context");
249            }
250            if (World == null)
251            {
252                throw new PuppeteerException("Cannot adopt handle without DOMWorld");
253            }
254
255            var nodeInfo = await _client.SendAsync<DomDescribeNodeResponse>("DOM.describeNode", new DomDescribeNodeRequest
256            {
257                ObjectId = elementHandle.RemoteObject.ObjectId
258            }).ConfigureAwait(false);
259
260            var obj = await _client.SendAsync<DomResolveNodeResponse>("DOM.resolveNode", new DomResolveNodeRequest
261            {
262                BackendNodeId = nodeInfo.Node.BackendNodeId,
263                ExecutionContextId = _contextId
264            }).ConfigureAwait(false);
265
266            return CreateJSHandle(obj.Object) as ElementHandle;
267        }
268    }
269}
Full Screen

Accelerate Your Automation Test Cycles With LambdaTest

Leverage LambdaTest’s cloud-based platform to execute your automation tests in parallel and trim down your test execution time significantly. Your first 100 automation testing minutes are on us.

Try LambdaTest

Trigger EvaluateExpressionInternalAsync code on LambdaTest Cloud Grid

Execute automation tests with EvaluateExpressionInternalAsync on a cloud-based Grid of 3000+ real browsers and operating systems for both web and mobile applications.

Test now for Free
LambdaTestX

We use cookies to give you the best experience. Cookies help to provide a more personalized experience and relevant advertising for you, and web analytics for us. Learn More in our Cookies policy, Privacy & Terms of service

Allow Cookie
Sarah

I hope you find the best code examples for your project.

If you want to accelerate automated browser testing, try LambdaTest. Your first 100 automation testing minutes are FREE.

Sarah Elson (Product & Growth Lead)