Skip to content

Commit

Permalink
Evaluate expressions on new document support (#1188)
Browse files Browse the repository at this point in the history
We are spliting EvaluateOnNewDocumentAsync into two methods. EvaluateFunctionOnNewDocumentAsync and EvaluateExpresionOnNewDocumentAsync.
  • Loading branch information
kblok authored Jun 26, 2019
1 parent 6b9f06f commit 3c037c3
Show file tree
Hide file tree
Showing 4 changed files with 79 additions and 33 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ public WaitForFunctionTests(ITestOutputHelper output) : base(output)
[Fact]
public async Task ShouldWorkWhenResolvedRightBeforeExecutionContextDisposal()
{
await Page.EvaluateOnNewDocumentAsync("() => window.__RELOADED = true");
await Page.EvaluateFunctionOnNewDocumentAsync("() => window.__RELOADED = true");
await Page.WaitForFunctionAsync(@"() =>
{
if (!window.__RELOADED)
Expand Down
12 changes: 10 additions & 2 deletions lib/PuppeteerSharp.Tests/PageTests/EvaluateOnNewDocumentTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public EvaluateOnNewDocumentTests(ITestOutputHelper output) : base(output)
[Fact]
public async Task ShouldEvaluateBeforeAnythingElseOnThePage()
{
await Page.EvaluateOnNewDocumentAsync(@"function(){
await Page.EvaluateFunctionOnNewDocumentAsync(@"function(){
window.injected = 123;
}");
await Page.GoToAsync(TestConstants.ServerUrl + "/tamperable.html");
Expand All @@ -29,7 +29,7 @@ await Page.EvaluateOnNewDocumentAsync(@"function(){
public async Task ShouldWorkWithCSP()
{
Server.SetCSP("/empty.html", "script-src " + TestConstants.ServerUrl);
await Page.EvaluateOnNewDocumentAsync(@"function(){
await Page.EvaluateFunctionOnNewDocumentAsync(@"function(){
window.injected = 123;
}");
await Page.GoToAsync(TestConstants.EmptyPage);
Expand All @@ -42,5 +42,13 @@ await Page.AddScriptTagAsync(new AddTagOptions
}).ContinueWith(_ => Task.CompletedTask);
Assert.Null(await Page.EvaluateExpressionAsync("window.e"));
}

[Fact]
public async Task ShouldWorkWithExpressions()
{
await Page.EvaluateExpressionOnNewDocumentAsync("window.injected = 123;");
await Page.GoToAsync(TestConstants.ServerUrl + "/tamperable.html");
Assert.Equal(123, await Page.EvaluateExpressionAsync<int>("window.result"));
}
}
}
2 changes: 1 addition & 1 deletion lib/PuppeteerSharp.Tests/PageTests/ExposeFunctionTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ public async Task ShouldBeCallableFromInsideEvaluateOnNewDocument()
{
var called = false;
await Page.ExposeFunctionAsync("woof", () => called = true);
await Page.EvaluateOnNewDocumentAsync("() => woof()");
await Page.EvaluateFunctionOnNewDocumentAsync("() => woof()");
await Page.ReloadAsync();
Assert.True(called);
}
Expand Down
96 changes: 67 additions & 29 deletions lib/PuppeteerSharp/Page.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@ public class Page : IDisposable
private PageGetLayoutMetricsResponse _burstModeMetrics;
private bool _screenshotBurstModeOn;
private ScreenshotOptions _screenshotBurstModeOptions;
private TaskCompletionSource<bool> _closeCompletedTcs = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
private TimeoutSettings _timeoutSettings;
private readonly TaskCompletionSource<bool> _closeCompletedTcs = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
private readonly TimeoutSettings _timeoutSettings;

private static readonly Dictionary<string, decimal> _unitToPixels = new Dictionary<string, decimal> {
{"px", 1},
Expand Down Expand Up @@ -105,7 +105,7 @@ private Page(
public event EventHandler<ErrorEventArgs> Error;

/// <summary>
/// Raised when the JavaScript code makes a call to <c>console.timeStamp</c>. For the list of metrics see <see cref="Page.MetricsAsync"/>.
/// Raised when the JavaScript code makes a call to <c>console.timeStamp</c>. For the list of metrics see <see cref="MetricsAsync"/>.
/// </summary>
public event EventHandler<MetricEventArgs> Metrics;

Expand Down Expand Up @@ -218,18 +218,18 @@ public int DefaultNavigationTimeout

/// <summary>
/// This setting will change the default maximum times for the following methods:
/// - <see cref="Page.GoBackAsync(NavigationOptions)"/>
/// - <see cref="Page.GoForwardAsync(NavigationOptions)"/>
/// - <see cref="Page.GoToAsync(string, NavigationOptions)"/>
/// - <see cref="Page.ReloadAsync(NavigationOptions)"/>
/// - <see cref="Page.SetContentAsync(string, NavigationOptions)"/>
/// - <see cref="Page.WaitForFunctionAsync(string, object[])"/>
/// - <see cref="Page.WaitForNavigationAsync(NavigationOptions)"/>
/// - <see cref="Page.WaitForRequestAsync(string, WaitForOptions)"/>
/// - <see cref="Page.WaitForResponseAsync(string, WaitForOptions)"/>
/// - <see cref="Page.WaitForXPathAsync(string, WaitForSelectorOptions)"/>
/// - <see cref="Page.WaitForSelectorAsync(string, WaitForSelectorOptions)"/>
/// - <see cref="Page.WaitForExpressionAsync(string, WaitForFunctionOptions)"/>
/// - <see cref="GoBackAsync(NavigationOptions)"/>
/// - <see cref="GoForwardAsync(NavigationOptions)"/>
/// - <see cref="GoToAsync(string, NavigationOptions)"/>
/// - <see cref="ReloadAsync(NavigationOptions)"/>
/// - <see cref="SetContentAsync(string, NavigationOptions)"/>
/// - <see cref="WaitForFunctionAsync(string, object[])"/>
/// - <see cref="WaitForNavigationAsync(NavigationOptions)"/>
/// - <see cref="WaitForRequestAsync(string, WaitForOptions)"/>
/// - <see cref="WaitForResponseAsync(string, WaitForOptions)"/>
/// - <see cref="WaitForXPathAsync(string, WaitForSelectorOptions)"/>
/// - <see cref="WaitForSelectorAsync(string, WaitForSelectorOptions)"/>
/// - <see cref="WaitForExpressionAsync(string, WaitForFunctionOptions)"/>
/// </summary>
public int DefaultTimeout
{
Expand Down Expand Up @@ -487,7 +487,28 @@ public async Task<JSHandle> EvaluateFunctionHandleAsync(string pageFunction, par
/// </code>
/// </example>
/// <returns>Task</returns>
[Obsolete("User EvaluateFunctionOnNewDocumentAsync instead")]
public Task EvaluateOnNewDocumentAsync(string pageFunction, params object[] args)
=> EvaluateFunctionOnNewDocumentAsync(pageFunction, args);

/// <summary>
/// Adds a function which would be invoked in one of the following scenarios:
/// - whenever the page is navigated
/// - whenever the child frame is attached or navigated. In this case, the function is invoked in the context of the newly attached frame
/// </summary>
/// <param name="pageFunction">Function to be evaluated in browser context</param>
/// <param name="args">Arguments to pass to <c>pageFunction</c></param>
/// <remarks>
/// The function is invoked after the document was created but before any of its scripts were run. This is useful to amend JavaScript environment, e.g. to seed <c>Math.random</c>.
/// </remarks>
/// <example>
/// An example of overriding the navigator.languages property before the page loads:
/// <code>
/// await page.EvaluateFunctionOnNewDocumentAsync("() => window.__example = true");
/// </code>
/// </example>
/// <returns>Task</returns>
public Task EvaluateFunctionOnNewDocumentAsync(string pageFunction, params object[] args)
{
var source = EvaluationString(pageFunction, args);
return Client.SendAsync("Page.addScriptToEvaluateOnNewDocument", new PageAddScriptToEvaluateOnNewDocumentRequest
Expand All @@ -496,6 +517,28 @@ public Task EvaluateOnNewDocumentAsync(string pageFunction, params object[] args
});
}

/// <summary>
/// Adds a function which would be invoked in one of the following scenarios:
/// - whenever the page is navigated
/// - whenever the child frame is attached or navigated. In this case, the function is invoked in the context of the newly attached frame
/// </summary>
/// <param name="expression">Javascript expression to be evaluated in browser context</param>
/// <remarks>
/// The function is invoked after the document was created but before any of its scripts were run. This is useful to amend JavaScript environment, e.g. to seed <c>Math.random</c>.
/// </remarks>
/// <example>
/// An example of overriding the navigator.languages property before the page loads:
/// <code>
/// await page.EvaluateExpressionOnNewDocumentAsync("window.__example = true;");
/// </code>
/// </example>
/// <returns>Task</returns>
public Task EvaluateExpressionOnNewDocumentAsync(string expression)
=> Client.SendAsync("Page.addScriptToEvaluateOnNewDocument", new PageAddScriptToEvaluateOnNewDocumentRequest
{
Source = expression
});

/// <summary>
/// The method iterates JavaScript heap and finds all the objects with the given prototype.
/// Shortcut for <c>page.MainFrame.GetExecutionContextAsync().QueryObjectsAsync(prototypeHandle)</c>.
Expand Down Expand Up @@ -1095,13 +1138,11 @@ public Task CloseAsync(PageCloseOptions options = null)
{
return Client.SendAsync("Page.close");
}
else

return Client.Connection.SendAsync("Target.closeTarget", new TargetCloseTargetRequest
{
return Client.Connection.SendAsync("Target.closeTarget", new TargetCloseTargetRequest
{
TargetId = Target.TargetId
}).ContinueWith(task => Target.CloseTask);
}
TargetId = Target.TargetId
}).ContinueWith(task => Target.CloseTask);
}

_logger.LogWarning("Protocol error: Connection closed. Most likely the page has been closed.");
Expand All @@ -1117,7 +1158,7 @@ public Task SetCacheEnabledAsync(bool enabled = true)
=> FrameManager.NetworkManager.SetCacheEnabledAsync(enabled);

/// <summary>
/// Fetches an element with <paramref name="selector"/>, scrolls it into view if needed, and then uses <see cref="Page.Mouse"/> to click in the center of the element.
/// Fetches an element with <paramref name="selector"/>, scrolls it into view if needed, and then uses <see cref="Mouse"/> to click in the center of the element.
/// </summary>
/// <param name="selector">A selector to search for element to click. If there are multiple elements satisfying the selector, the first will be clicked.</param>
/// <param name="options">click options</param>
Expand All @@ -1126,7 +1167,7 @@ public Task SetCacheEnabledAsync(bool enabled = true)
public Task ClickAsync(string selector, ClickOptions options = null) => FrameManager.MainFrame.ClickAsync(selector, options);

/// <summary>
/// Fetches an element with <paramref name="selector"/>, scrolls it into view if needed, and then uses <see cref="Page.Mouse"/> to hover over the center of the element.
/// Fetches an element with <paramref name="selector"/>, scrolls it into view if needed, and then uses <see cref="Mouse"/> to hover over the center of the element.
/// </summary>
/// <param name="selector">A selector to search for element to hover. If there are multiple elements satisfying the selector, the first will be hovered.</param>
/// <exception cref="SelectorException">If there's no element matching <paramref name="selector"/></exception>
Expand Down Expand Up @@ -1754,8 +1795,7 @@ private decimal ConvertPrintParameterToInches(object parameter)
return 0;
}

var pixels = 0m;

decimal pixels;
if (parameter is decimal || parameter is int)
{
pixels = Convert.ToDecimal(parameter);
Expand All @@ -1764,8 +1804,7 @@ private decimal ConvertPrintParameterToInches(object parameter)
{
var text = parameter.ToString();
var unit = text.Substring(text.Length - 2).ToLower();
var valueText = "";

string valueText;
if (_unitToPixels.ContainsKey(unit))
{
valueText = text.Substring(0, text.Length - 2);
Expand Down Expand Up @@ -1842,8 +1881,7 @@ private async void Client_MessageReceived(object sender, MessageEventArgs e)

private async Task OnBindingCalled(BindingCalledResponse e)
{
string expression = null;

string expression;
try
{
var result = await ExecuteBinding(e).ConfigureAwait(false);
Expand Down

0 comments on commit 3c037c3

Please sign in to comment.