diff --git a/src/Playwright.Tests/Locator/LocatorQueryTests.cs b/src/Playwright.Tests/Locator/LocatorQueryTests.cs
new file mode 100644
index 0000000000..af0996f77c
--- /dev/null
+++ b/src/Playwright.Tests/Locator/LocatorQueryTests.cs
@@ -0,0 +1,85 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) Microsoft Corporation.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+using System.Threading.Tasks;
+using NUnit.Framework;
+
+namespace Microsoft.Playwright.Tests.Locator
+{
+ public class LocatorQueryTests : PageTestEx
+ {
+ [PlaywrightTest("locator-query.spec.ts", "should respect first() and last()")]
+ public async Task ShouldRespectFirstAndLast()
+ {
+ await Page.SetContentAsync(@"
+
+
");
+ var exception = await PlaywrightAssert.ThrowsAsync(() => Page.Locator("*css=div >> p").Nth(1).ClickAsync());
+ StringAssert.Contains("Can't query n-th element", exception.Message);
+ }
+
+ [PlaywrightTest("locator-query.spec.ts", "should throw on due to strictness")]
+ public async Task ShouldThrowDueToStrictness()
+ {
+ await Page.SetContentAsync("
A
B
");
+ var exception = await PlaywrightAssert.ThrowsAsync(() => Page.Locator("div").IsVisibleAsync());
+ StringAssert.Contains("strict mode violation", exception.Message);
+ }
+
+ [PlaywrightTest("locator-query.spec.ts", "should throw on due to strictness 2")]
+ public async Task ShouldThrowDueToStrictness2()
+ {
+ await Page.SetContentAsync("");
+ var exception = await PlaywrightAssert.ThrowsAsync(() => Page.Locator("option").EvaluateAsync("() => {}"));
+ StringAssert.Contains("strict mode violation", exception.Message);
+ }
+ }
+}
diff --git a/src/Playwright/API/Supplements/ILocator.cs b/src/Playwright/API/Supplements/ILocator.cs
new file mode 100644
index 0000000000..0d57c2103e
--- /dev/null
+++ b/src/Playwright/API/Supplements/ILocator.cs
@@ -0,0 +1,34 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) Microsoft Corporation.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+using System.Text.Json;
+using System.Threading.Tasks;
+
+namespace Microsoft.Playwright
+{
+ public partial interface ILocator
+ {
+ Task EvaluateAsync(string expression, object arg = null, LocatorEvaluateOptions options = null);
+ }
+}
diff --git a/src/Playwright/Core/Locator.cs b/src/Playwright/Core/Locator.cs
index a7a4ed7237..9a8fa794a0 100644
--- a/src/Playwright/Core/Locator.cs
+++ b/src/Playwright/Core/Locator.cs
@@ -43,9 +43,9 @@ public Locator(Frame parent, string selector)
_selector = selector;
}
- public ILocator First => new Locator(_frame, $"{_selector} >> _nth=first");
+ public ILocator First => new Locator(_frame, $"{_selector} >> nth=0");
- public ILocator Last => new Locator(_frame, $"{_selector} >> _nth=last");
+ public ILocator Last => new Locator(_frame, $"{_selector} >> nth=-1");
public async Task> AllInnerTextsAsync()
{
@@ -121,6 +121,9 @@ public Task> ElementHandlesAsync()
public Task EvaluateAllAsync(string expression, object arg = null)
=> _frame.EvalOnSelectorAllAsync(_selector, expression, arg);
+ public Task EvaluateAsync(string expression, object arg = null, LocatorEvaluateOptions options = null)
+ => EvaluateAsync(expression, arg, options);
+
public Task EvaluateAsync(string expression, object arg = null, LocatorEvaluateOptions options = null)
=> _frame.EvalOnSelectorAsync(_selector, expression, arg, ConvertOptions(options));
@@ -167,7 +170,7 @@ public Task IsVisibleAsync(LocatorIsVisibleOptions options = null)
=> _frame.IsVisibleAsync(_selector, ConvertOptions(options));
public ILocator Nth(int index)
- => new Locator(_frame, $"{_selector} >> _nth=${index}");
+ => new Locator(_frame, $"{_selector} >> nth={index}");
public Task PressAsync(string key, LocatorPressOptions options = null)
=> _frame.PressAsync(_selector, key, ConvertOptions(options));