Skip to content

Commit 2900d12

Browse files
Meir017kblok
authored andcommitted
Implement Page.QuerySelectorAsync (a.k.a. Page.$) (#196)
1 parent f7913e1 commit 2900d12

File tree

9 files changed

+64
-27
lines changed

9 files changed

+64
-27
lines changed

lib/PuppeteerSharp.Tests/Frame/WaitForFunctionTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ public async Task ShouldReturnTheWindowAsASuccessValue()
6969
public async Task ShouldAcceptElementHandleArguments()
7070
{
7171
await Page.SetContentAsync("<div></div>");
72-
var div = await Page.GetElementAsync("div");
72+
var div = await Page.QuerySelectorAsync("div");
7373
var resolved = false;
7474
var waitForFunction = Page.WaitForFunctionAsync("element => !element.parentElement", div)
7575
.ContinueWith(_ => resolved = true);

lib/PuppeteerSharp.Tests/Input/InputTests.cs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ public async Task ShouldTypeIntoTheTextarea()
8888
{
8989
await Page.GoToAsync(TestConstants.ServerUrl + "/input/textarea.html");
9090

91-
var textarea = await Page.GetElementAsync("textarea");
91+
var textarea = await Page.QuerySelectorAsync("textarea");
9292
await textarea.TypeAsync("Type in this text!");
9393
Assert.Equal("Type in this text!", await Page.EvaluateExpressionAsync<string>("result"));
9494
}
@@ -108,7 +108,7 @@ public async Task ShouldUploadTheFile()
108108
{
109109
await Page.GoToAsync(TestConstants.ServerUrl + "/input/fileupload.html");
110110
var filePath = "./assets/file-to-upload.txt";
111-
var input = await Page.GetElementAsync("input");
111+
var input = await Page.QuerySelectorAsync("input");
112112
await input.UploadFileAsync(filePath);
113113
Assert.Equal("file-to-upload.txt", await Page.EvaluateFunctionAsync<string>("e => e.files[0].name", input));
114114
Assert.Equal("contents of the file", await Page.EvaluateFunctionAsync(@"e => {
@@ -147,7 +147,7 @@ public async Task ShouldMoveWithTheArrowKeys()
147147
public async Task ShouldSendACharacterWithElementHandlePress()
148148
{
149149
await Page.GoToAsync(TestConstants.ServerUrl + "/input/textarea.html");
150-
var textarea = await Page.GetElementAsync("textarea");
150+
var textarea = await Page.QuerySelectorAsync("textarea");
151151
await textarea.PressAsync("a", new PressOptions { Text = "f" });
152152
Assert.Equal("f", await Page.EvaluateExpressionAsync<string>("document.querySelector('textarea').value"));
153153

@@ -316,7 +316,7 @@ await Page.EvaluateExpressionAsync(@"{
316316
window.double = true;
317317
});
318318
}");
319-
var button = await Page.GetElementAsync("button");
319+
var button = await Page.QuerySelectorAsync("button");
320320
await button.ClickAsync(new ClickOptions { ClickCount = 2 });
321321
Assert.True(await Page.EvaluateExpressionAsync<bool>("double"));
322322
Assert.Equal("Clicked", await Page.EvaluateExpressionAsync<string>("result"));
@@ -465,7 +465,7 @@ public async Task ShouldTapTheButton()
465465
public async Task ShouldReportTouches()
466466
{
467467
await Page.GoToAsync(TestConstants.ServerUrl + "/input/touches.html");
468-
var button = await Page.GetElementAsync("button");
468+
var button = await Page.QuerySelectorAsync("button");
469469
await button.TapAsync();
470470
Assert.Equal(new object[] {
471471
new { Touchstart = 0 },
@@ -480,7 +480,7 @@ public async Task ShouldClickTheButtonInsideAnIframe()
480480
await Page.SetContentAsync("<div style=\"width:100px;height:100px\">spacer</div>");
481481
await FrameUtils.AttachFrameAsync(Page, "button-test", TestConstants.ServerUrl + "/input/button.html");
482482
var frame = Page.Frames[1];
483-
var button = await frame.GetElementAsync("button");
483+
var button = await frame.QuerySelectorAsync("button");
484484
await button.ClickAsync();
485485
Assert.Equal("Clicked", await frame.EvaluateExpressionAsync<string>("window.result"));
486486
}
@@ -493,7 +493,7 @@ public async Task ShouldClickTheButtonWithDeviceScaleFactorSet()
493493
await Page.SetContentAsync("<div style=\"width:100px;height:100px\">spacer</div>");
494494
await FrameUtils.AttachFrameAsync(Page, "button-test", TestConstants.ServerUrl + "/input/button.html");
495495
var frame = Page.Frames[1];
496-
var button = await frame.GetElementAsync("button");
496+
var button = await frame.QuerySelectorAsync("button");
497497
await button.ClickAsync();
498498
Assert.Equal("Clicked", await frame.EvaluateExpressionAsync<string>("window.result"));
499499
}
@@ -515,7 +515,7 @@ public async Task ShouldSpecifyLocation()
515515
await Page.EvaluateExpressionAsync(@"{
516516
window.addEventListener('keydown', event => window.keyLocation = event.location, true);
517517
}");
518-
var textarea = await Page.GetElementAsync("textarea");
518+
var textarea = await Page.QuerySelectorAsync("textarea");
519519

520520
await textarea.PressAsync("Digit5");
521521
Assert.Equal(0, await Page.EvaluateExpressionAsync<int>("keyLocation"));

lib/PuppeteerSharp.Tests/Page/EmulateTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ public async Task ShouldSupportClicking()
2121
{
2222
await Page.EmulateAsync(TestConstants.IPhone);
2323
await Page.GoToAsync(TestConstants.ServerUrl + "/input/button.html");
24-
var button = await Page.GetElementAsync("button");
24+
var button = await Page.QuerySelectorAsync("button");
2525
await Page.EvaluateFunctionAsync("button => button.style.marginTop = '200px'", button);
2626
await button.ClickAsync();
2727
Assert.Equal("Clicked", await Page.EvaluateExpressionAsync<string>("result"));

lib/PuppeteerSharp.Tests/Page/EvalTests.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,32 +10,32 @@ public class EvalTests : PuppeteerPageBaseTest
1010
public async Task ShouldWork()
1111
{
1212
await Page.SetContentAsync("<section id='testAttribute'>43543</section>");
13-
var idAttribute = await Page.GetElementAsync("section").EvaluateFunctionAsync<string>("e => e.id");
13+
var idAttribute = await Page.QuerySelectorAsync("section").EvaluateFunctionAsync<string>("e => e.id");
1414
Assert.Equal("testAttribute", idAttribute);
1515
}
1616

1717
[Fact]
1818
public async Task ShouldAcceptArguments()
1919
{
2020
await Page.SetContentAsync("<section>hello</section>");
21-
var text = await Page.GetElementAsync("section").EvaluateFunctionAsync<string>("(e, suffix) => e.textContent + suffix", " world!");
21+
var text = await Page.QuerySelectorAsync("section").EvaluateFunctionAsync<string>("(e, suffix) => e.textContent + suffix", " world!");
2222
Assert.Equal("hello world!", text);
2323
}
2424

2525
[Fact]
2626
public async Task ShouldAcceptElementHandlesAsArguments()
2727
{
2828
await Page.SetContentAsync("<section>hello</section><div> world</div>");
29-
var divHandle = await Page.GetElementAsync("div");
30-
var text = await Page.GetElementAsync("section").EvaluateFunctionAsync<string>("(e, div) => e.textContent + div.textContent", divHandle);
29+
var divHandle = await Page.QuerySelectorAsync("div");
30+
var text = await Page.QuerySelectorAsync("section").EvaluateFunctionAsync<string>("(e, div) => e.textContent + div.textContent", divHandle);
3131
Assert.Equal("hello world", text);
3232
}
3333

3434
[Fact]
3535
public async Task ShouldThrowErrorIfNoElementIsFound()
3636
{
3737
var exception = await Assert.ThrowsAsync<SelectorException>(()
38-
=> Page.GetElementAsync("section").EvaluateFunctionAsync<string>("e => e.id"));
38+
=> Page.QuerySelectorAsync("section").EvaluateFunctionAsync<string>("e => e.id"));
3939
Assert.Contains("failed to find element matching selector", exception.Message);
4040
}
4141
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
using System.Threading.Tasks;
2+
using Xunit;
3+
4+
namespace PuppeteerSharp.Tests.Page
5+
{
6+
[Collection("PuppeteerLoaderFixture collection")]
7+
public class QuerySelectorTests : PuppeteerPageBaseTest
8+
{
9+
[Fact]
10+
public async Task ShouldQueryExistingElement()
11+
{
12+
await Page.SetContentAsync("<section>test</section>");
13+
var element = await Page.QuerySelectorAsync("section");
14+
Assert.NotNull(element);
15+
}
16+
17+
[Fact]
18+
public async Task ShouldReturnNullForNonExistingElement()
19+
{
20+
var element = await Page.QuerySelectorAsync("non-existing-element");
21+
Assert.Null(element);
22+
}
23+
}
24+
}

lib/PuppeteerSharp.Tests/Target/TargetTests.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ public async Task ShouldBeAbleToUseTheDefaultPageInTheBrowser()
3737
var allPages = await Browser.PagesAsync();
3838
var originalPage = allPages.First(p => p != Page);
3939
Assert.Equal("Hello world", await originalPage.EvaluateExpressionAsync<string>("['Hello', 'world'].join(' ')"));
40-
Assert.NotNull(await originalPage.GetElementAsync("body"));
40+
Assert.NotNull(await originalPage.QuerySelectorAsync("body"));
4141
}
4242

4343
[Fact]
@@ -55,7 +55,7 @@ async void TargetCreatedEventHandler(object sender, TargetChangedArgs e)
5555
Assert.Contains(TestConstants.CrossProcessUrl, otherPage.Url);
5656

5757
Assert.Equal("Hello world", await otherPage.EvaluateExpressionAsync<string>("['Hello', 'world'].join(' ')"));
58-
Assert.NotNull(await otherPage.GetElementAsync("body"));
58+
Assert.NotNull(await otherPage.QuerySelectorAsync("body"));
5959

6060
var allPages = await Browser.PagesAsync();
6161
Assert.Contains(Page, allPages);

lib/PuppeteerSharp/ElementHandle.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ public async Task PressAsync(string key, PressOptions options = null)
112112
await Page.Keyboard.PressAsync(key, options);
113113
}
114114

115-
internal async Task<ElementHandle> GetElementAsync(string selector)
115+
internal async Task<ElementHandle> QuerySelectorAsync(string selector)
116116
{
117117
var handle = await ExecutionContext.EvaluateFunctionHandleAsync(
118118
"(element, selector) => element.querySelector(selector)",

lib/PuppeteerSharp/Frame.cs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -122,10 +122,15 @@ public async Task<T> EvaluateFunctionAsync<T>(string script, params object[] arg
122122
/// <returns><see cref="ExecutionContext"/> associated with the frame.</returns>
123123
public Task<ExecutionContext> GetExecutionContextAsync() => ContextResolveTaskWrapper.Task;
124124

125-
internal async Task<ElementHandle> GetElementAsync(string selector)
125+
/// <summary>
126+
/// Queries frame for the selector. If there's no such element within the frame, the method will resolve to <c>null</c>.
127+
/// </summary>
128+
/// <param name="selector">Selector to query page for</param>
129+
/// <returns>Task which resolves to <see cref="ElementHandle"/> pointing to the frame element</returns>
130+
internal async Task<ElementHandle> QuerySelectorAsync(string selector)
126131
{
127132
var document = await GetDocument();
128-
var value = await document.GetElementAsync(selector);
133+
var value = await document.QuerySelectorAsync(selector);
129134
return value;
130135
}
131136

lib/PuppeteerSharp/Page.cs

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ public async Task<Dictionary<string, decimal>> MetricsAsync()
152152
/// <returns>Task which resolves when the element matching <paramref name="selector"/> is successfully tapped</returns>
153153
public async Task TapAsync(string selector)
154154
{
155-
var handle = await GetElementAsync(selector);
155+
var handle = await QuerySelectorAsync(selector);
156156
if (handle == null)
157157
{
158158
throw new SelectorException($"No node found for selector: {selector}", selector);
@@ -161,8 +161,16 @@ public async Task TapAsync(string selector)
161161
await handle.DisposeAsync();
162162
}
163163

164-
public async Task<ElementHandle> GetElementAsync(string selector)
165-
=> await MainFrame.GetElementAsync(selector);
164+
/// <summary>
165+
/// The method runs <c>document.querySelector</c> within the page. If no element matches the selector, the return value resolve to <c>null</c>.
166+
/// </summary>
167+
/// <param name="selector">A selector to query page for</param>
168+
/// <returns>Task which resolves to <see cref="ElementHandle"/> pointing to the frame element</returns>
169+
/// <remarks>
170+
/// Shortcut for <c>page.MainFrame.QuerySelectorAsync(selector)</c>
171+
/// </remarks>
172+
public async Task<ElementHandle> QuerySelectorAsync(string selector)
173+
=> await MainFrame.QuerySelectorAsync(selector);
166174

167175
/// <summary>
168176
/// Runs <c>document.querySelectorAll</c> within the page. If no elements match the selector, the return value resolve to <see cref="Array.Empty{T}"/>.
@@ -692,7 +700,7 @@ public Task CloseAsync()
692700
/// <returns>Task which resolves when the element matching <paramref name="selector"/> is successfully clicked</returns>
693701
public async Task ClickAsync(string selector, ClickOptions options = null)
694702
{
695-
var handle = await GetElementAsync(selector);
703+
var handle = await QuerySelectorAsync(selector);
696704
if (handle == null)
697705
{
698706
throw new SelectorException($"No node found for selector: {selector}", selector);
@@ -709,7 +717,7 @@ public async Task ClickAsync(string selector, ClickOptions options = null)
709717
/// <returns>Task which resolves when the element matching <paramref name="selector"/> is successfully hovered</returns>
710718
public async Task HoverAsync(string selector)
711719
{
712-
var handle = await GetElementAsync(selector);
720+
var handle = await QuerySelectorAsync(selector);
713721
if (handle == null)
714722
{
715723
throw new SelectorException($"No node found for selector: {selector}", selector);
@@ -726,7 +734,7 @@ public async Task HoverAsync(string selector)
726734
/// <returns>Task which resolves when the element matching <paramref name="selector"/> is successfully focused</returns>
727735
public async Task FocusAsync(string selector)
728736
{
729-
var handle = await GetElementAsync(selector);
737+
var handle = await QuerySelectorAsync(selector);
730738
if (handle == null)
731739
{
732740
throw new SelectorException($"No node found for selector: {selector}", selector);
@@ -786,7 +794,7 @@ await Task.WhenAll(
786794
/// <returns>Task</returns>
787795
public async Task TypeAsync(string selector, string text, TypeOptions options = null)
788796
{
789-
var handle = await GetElementAsync(selector);
797+
var handle = await QuerySelectorAsync(selector);
790798
if (handle == null)
791799
{
792800
throw new SelectorException($"No node found for selector: {selector}", selector);

0 commit comments

Comments
 (0)