diff --git a/README.md b/README.md index d4db4ac..801560c 100644 --- a/README.md +++ b/README.md @@ -88,6 +88,7 @@ coreWebView2.NavigationCompleted += async (sender, args) => var htmlTextAreaElement = await devToolsContext.QuerySelectorAsync("#myTextAreaElementId"); var htmlButtonElement = await devToolsContext.QuerySelectorAsync("#myButtonElementId"); var htmlParagraphElement = await devToolsContext.QuerySelectorAsync("#myParagraphElementId"); + var htmlTableElement = await devToolsContext.QuerySelectorAsync("#myTableElementId"); // Get a custom attribute value var customAttribute = await element.GetAttributeAsync("data-customAttribute"); @@ -134,7 +135,7 @@ coreWebView2.NavigationCompleted += async (sender, args) => _ = jsAlertButton.AddEventListenerAsync("click", "jsAlertButtonClick"); //Get a collection of HtmlElements - var divElements = await devToolsContext.QuerySelectorAllAsync("div"); + var divElements = await devToolsContext.QuerySelectorAllAsync("div"); foreach (var div in divElements) { @@ -147,10 +148,39 @@ coreWebView2.NavigationCompleted += async (sender, args) => await div.SetAttributeAsync("data-customAttribute", "123"); await div.SetInnerTextAsync("Updated Div innerText"); } + + //Using standard array + var tableRows = await htmlTableElement.GetRowsAsync().ToArrayAsync(); + + foreach(var row in tableRows) + { + var cells = await row.GetCellsAsync().ToArrayAsync(); + foreach(var cell in cells) + { + var newDiv = await devToolsContext.CreateHtmlElementAsync("div"); + await newDiv.SetInnerTextAsync("New Div Added!"); + await cell.AppendChildAsync(newDiv); + } + } + + //Get a reference to the HtmlCollection and use async enumerable + //Requires Net Core 3.1 or higher + var tableRowsHtmlCollection = await htmlTableElement.GetRowsAsync(); + + await foreach (var row in tableRowsHtmlCollection) + { + var cells = await row.GetCellsAsync(); + await foreach (var cell in cells) + { + var newDiv = await devToolsContext.CreateHtmlElementAsync("div"); + await newDiv.SetInnerTextAsync("New Div Added!"); + await cell.AppendChildAsync(newDiv); + } + } } }; ``` -snippet source | anchor +snippet source | anchor ## Inject HTML diff --git a/WebView2.DevTools.Dom.Tests/ClickTests/ClickTests.cs b/WebView2.DevTools.Dom.Tests/ClickTests/ClickTests.cs index 98cf808..bffb134 100644 --- a/WebView2.DevTools.Dom.Tests/ClickTests/ClickTests.cs +++ b/WebView2.DevTools.Dom.Tests/ClickTests/ClickTests.cs @@ -94,7 +94,7 @@ public async Task ShouldSelectTheTextByTripleClicking() await WebView.CoreWebView2.NavigateToAsync(TestConstants.ServerUrl + "/input/textarea.html"); await DevToolsContext.FocusAsync("textarea"); - + await DevToolsContext.Keyboard.TypeAsync(expected); await DevToolsContext.ClickAsync("textarea"); await DevToolsContext.ClickAsync("textarea", new ClickOptions { ClickCount = 2 }); @@ -221,7 +221,7 @@ await DevToolsContext.EvaluateExpressionAsync(@"{ window.double = true; }); }"); - var button = await DevToolsContext.QuerySelectorAsync("button"); + var button = await DevToolsContext.QuerySelectorAsync("button"); await button.ClickAsync(new ClickOptions { ClickCount = 2 }); Assert.True(await DevToolsContext.EvaluateExpressionAsync("double")); Assert.Equal("Clicked", await DevToolsContext.EvaluateExpressionAsync("result")); @@ -273,7 +273,7 @@ public async Task ShouldClickTheButtonInsideAnIframe() await DevToolsContext.SetContentAsync("
spacer
"); await FrameUtils.AttachFrameAsync(DevToolsContext, "button-test", TestConstants.ServerUrl + "/input/button.html"); var frame = DevToolsContext.FirstChildFrame(); - var button = await frame.QuerySelectorAsync("button"); + var button = await frame.QuerySelectorAsync("button"); await button.ClickAsync(); Assert.Equal("Clicked", await frame.EvaluateExpressionAsync("window.result")); } @@ -295,7 +295,7 @@ await DevToolsContext.SetViewportAsync(new ViewPortOptions Assert.Equal("Clicked", await frame.EvaluateExpressionAsync("window.result")); } - [WebView2ContextFact()] + [WebView2ContextFact] public async Task ShouldClickTheButtonWithDeviceScaleFactorSet() { await DevToolsContext.SetViewportAsync(new ViewPortOptions { Width = 400, Height = 400, DeviceScaleFactor = 5 }); @@ -303,7 +303,7 @@ public async Task ShouldClickTheButtonWithDeviceScaleFactorSet() await DevToolsContext.SetContentAsync("
spacer
"); await FrameUtils.AttachFrameAsync(DevToolsContext, "button-test", TestConstants.ServerUrl + "/input/button.html"); var frame = DevToolsContext.FirstChildFrame(); - var button = await frame.QuerySelectorAsync("button"); + var button = await frame.QuerySelectorAsync("button"); await button.ClickAsync(); Assert.Equal("Clicked", await frame.EvaluateExpressionAsync("window.result")); } diff --git a/WebView2.DevTools.Dom.Tests/DevToolsContextTests/AddHtmlElementTests.cs b/WebView2.DevTools.Dom.Tests/DevToolsContextTests/AddHtmlElementTests.cs new file mode 100644 index 0000000..e31e405 --- /dev/null +++ b/WebView2.DevTools.Dom.Tests/DevToolsContextTests/AddHtmlElementTests.cs @@ -0,0 +1,43 @@ +using System.Threading.Tasks; +using WebView2.DevTools.Dom.Tests.Attributes; +using Xunit; +using Xunit.Abstractions; + +namespace WebView2.DevTools.Dom.Tests.DevToolsContextTests +{ + [Collection(TestConstants.TestFixtureCollectionName)] + public class AddHtmlElementTests : DevTooolsContextBaseTest + { + public AddHtmlElementTests(ITestOutputHelper output) : base(output) + { + } + + [WebView2ContextFact] + public async Task ShouldCreateDiv() + { + const string expected = ""; + + await WebView.CoreWebView2.NavigateToAsync(TestConstants.EmptyPage); + var div = await DevToolsContext.CreateHtmlElementAsync("div"); + Assert.NotNull(div); + + var actual = await div.GetIdAsync(); + + Assert.Equal(expected, actual); + } + + [WebView2ContextFact] + public async Task ShouldCreateDivWithId() + { + const string expected = "myDiv"; + + await WebView.CoreWebView2.NavigateToAsync(TestConstants.EmptyPage); + var div = await DevToolsContext.CreateHtmlElementAsync("div", expected); + Assert.NotNull(div); + + var actual = await div.GetIdAsync(); + + Assert.Equal(expected, actual); + } + } +} diff --git a/WebView2.DevTools.Dom.Tests/DevToolsContextTests/PageEventsPageErrorTests.cs b/WebView2.DevTools.Dom.Tests/DevToolsContextTests/PageEventsPageErrorTests.cs new file mode 100644 index 0000000..2d8d7b2 --- /dev/null +++ b/WebView2.DevTools.Dom.Tests/DevToolsContextTests/PageEventsPageErrorTests.cs @@ -0,0 +1,61 @@ +using System.Text.Json; +using System; +using System.Threading.Tasks; +using WebView2.DevTools.Dom; +using Microsoft.Web.WebView2.Core; +using WebView2.DevTools.Dom.Tests.Attributes; +using Xunit; +using Xunit.Abstractions; + +namespace WebView2.DevTools.Dom.Tests.DevToolsContextTests +{ + [Collection(TestConstants.TestFixtureCollectionName)] + public class PageEventsPageErrorTests : DevTooolsContextBaseTest + { + public PageEventsPageErrorTests(ITestOutputHelper output) : base(output) + { + } + + [WebView2ContextFact(Skip = "Possibly implement this")] + public Task ShouldFire() + { + throw new System.NotImplementedException(); + //string error = null; + //void EventHandler(object sender, PageErrorEventArgs e) + //{ + // error = e.Message; + // Page.PageError -= EventHandler; + //} + + //Page.PageError += EventHandler; + + //var completion = new TaskCompletionSource(); + + //var reciever = WebView.CoreWebView2.GetDevToolsProtocolEventReceiver("Runtime.exceptionThrown"); + + //reciever.DevToolsProtocolEventReceived += handler; + + //void handler(object sender, CoreWebView2DevToolsProtocolEventReceivedEventArgs e) + //{ + // var d = JsonDocument.Parse(e.ParameterObjectAsJson); + + // if (d.RootElement.GetProperty("MessageId").GetString() != "Runtime.exceptionThrown") + // { + // return; + // } + // reciever.DevToolsProtocolEventReceived -= handler; + // completion.SetResult(d.RootElement.GetProperty("MessageData").GetString()); + //} + + //reciever.DevToolsProtocolEventReceived += handler; + //return completion.Task; + + //await Task.WhenAll( + // WebView.CoreWebView2.NavigateToAsync(TestConstants.ServerUrl + "/error.html"), + // WaitEvent(, ) + //); + + //Assert.Contains("Fancy", error); + } + } +} diff --git a/WebView2.DevTools.Dom.Tests/DevToolsContextTests/SelectTests.cs b/WebView2.DevTools.Dom.Tests/DevToolsContextTests/SelectTests.cs index 9c819c1..5bc9bb7 100644 --- a/WebView2.DevTools.Dom.Tests/DevToolsContextTests/SelectTests.cs +++ b/WebView2.DevTools.Dom.Tests/DevToolsContextTests/SelectTests.cs @@ -1,6 +1,5 @@ using System; using System.Threading.Tasks; -using WebView2.DevTools.Dom; using WebView2.DevTools.Dom.Tests.Attributes; using Xunit; using Xunit.Abstractions; @@ -48,7 +47,11 @@ await Task.WhenAll( public async Task ShouldSelectMultipleOptions() { await WebView.CoreWebView2.NavigateToAsync(TestConstants.ServerUrl + "/input/select.html"); - await DevToolsContext.EvaluateExpressionAsync("makeMultiple()"); + + var select = await DevToolsContext.QuerySelectorAsync("select"); + + await select.SetMultipleAsync(true); + await DevToolsContext.SelectAsync("select", "blue", "green", "red"); Assert.Equal(new string[] { "blue", "green", "red" }, await DevToolsContext.EvaluateExpressionAsync("result.onInput")); @@ -85,7 +88,11 @@ public async Task ShouldReturnEmptyArrayOnNoMatchedValues() public async Task ShouldReturnAnArrayOfMatchedValues() { await WebView.CoreWebView2.NavigateToAsync(TestConstants.ServerUrl + "/input/select.html"); - await DevToolsContext.EvaluateExpressionAsync("makeMultiple()"); + + var select = await DevToolsContext.QuerySelectorAsync("select"); + + await select.SetMultipleAsync(true); + var result = await DevToolsContext.SelectAsync("select", "blue", "black", "magenta"); Array.Sort(result); Assert.Equal(new string[] { "black", "blue", "magenta" }, result); @@ -109,7 +116,11 @@ public async Task ShouldReturnEmptyArrayOnNoValues() public async Task ShouldDeselectAllOptionsWhenPassedNoValuesForAMultipleSelect() { await WebView.CoreWebView2.NavigateToAsync(TestConstants.ServerUrl + "/input/select.html"); - await DevToolsContext.EvaluateExpressionAsync("makeMultiple()"); + + var select = await DevToolsContext.QuerySelectorAsync("select"); + + await select.SetMultipleAsync(true); + await DevToolsContext.SelectAsync("select", "blue", "black", "magenta"); await DevToolsContext.SelectAsync("select"); Assert.True(await DevToolsContext.QuerySelectorAsync("select").EvaluateFunctionAsync( diff --git a/WebView2.DevTools.Dom.Tests/ElementHandleTests/HtmlTableCellElementTests.cs b/WebView2.DevTools.Dom.Tests/ElementHandleTests/HtmlTableCellElementTests.cs new file mode 100644 index 0000000..82f461f --- /dev/null +++ b/WebView2.DevTools.Dom.Tests/ElementHandleTests/HtmlTableCellElementTests.cs @@ -0,0 +1,112 @@ +using System.Threading.Tasks; +using WebView2.DevTools.Dom.Tests.Attributes; +using Xunit.Abstractions; +using Xunit; + +namespace WebView2.DevTools.Dom.Tests.ElementHandleTests +{ + + [Collection(TestConstants.TestFixtureCollectionName)] + public class HtmlTableCellElementTests : DevTooolsContextBaseTest + { + public HtmlTableCellElementTests(ITestOutputHelper output) : base(output) + { + } + + [WebView2ContextFact] + public async Task ShouldWork() + { + await WebView.CoreWebView2.NavigateToAsync(TestConstants.ServerUrl + "/table.html"); + var element = await DevToolsContext.QuerySelectorAsync("td"); + + Assert.NotNull(element); + } + + [WebView2ContextFact] + public async Task ShouldReturnNull() + { + await WebView.CoreWebView2.NavigateToAsync(TestConstants.ServerUrl + "/table.html"); + var element = await DevToolsContext.QuerySelectorAsync("#table2 td"); + + Assert.Null(element); + } + + [WebView2ContextFact] + public async Task ShouldGetIndex() + { + await WebView.CoreWebView2.NavigateToAsync(TestConstants.ServerUrl + "/table.html"); + var element = await DevToolsContext.QuerySelectorAsync("td"); + + var index = await element.GetCellIndexAsync(); + + Assert.True(index > -1); + } + + [WebView2ContextFact] + public async Task ShouldSetThenGetAbbr() + { + const string expected = "Testing"; + + await WebView.CoreWebView2.NavigateToAsync(TestConstants.ServerUrl + "/table.html"); + var element = await DevToolsContext.QuerySelectorAsync("td"); + + await element.SetAbbrAsync(expected); + var actual = await element.GetAbbrAsync(); + + Assert.Equal(expected, actual); + } + + [WebView2ContextFact] + public async Task ShouldGetScope() + { + await WebView.CoreWebView2.NavigateToAsync(TestConstants.ServerUrl + "/table.html"); + var element = await DevToolsContext.QuerySelectorAsync("td"); + + var actual = await element.GetScopeAsync(); + + Assert.Equal(string.Empty, actual); + } + + [WebView2ContextFact] + public async Task ShouldSetThenGetScope() + { + const string expected = "col"; + + await WebView.CoreWebView2.NavigateToAsync(TestConstants.ServerUrl + "/table.html"); + var element = await DevToolsContext.QuerySelectorAsync("td"); + + await element.SetScopeAsync(expected); + var actual = await element.GetScopeAsync(); + + Assert.Equal(expected, actual); + } + + [WebView2ContextFact] + public async Task ShouldSetThenGetRowSpan() + { + const int expected = 3; + + await WebView.CoreWebView2.NavigateToAsync(TestConstants.ServerUrl + "/table.html"); + var element = await DevToolsContext.QuerySelectorAsync("td"); + + await element.SetRowSpanAsync(expected); + var actual = await element.GetRowSpanAsync(); + + Assert.Equal(expected, actual); + } + + [WebView2ContextFact] + public async Task ShouldSetThenGetColSpan() + { + const int expected = 3; + + await WebView.CoreWebView2.NavigateToAsync(TestConstants.ServerUrl + "/table.html"); + var element = await DevToolsContext.QuerySelectorAsync("td"); + + await element.SetColSpanAsync(expected); + var actual = await element.GetColSpanAsync(); + + Assert.Equal(expected, actual); + } + } +} diff --git a/WebView2.DevTools.Dom.Tests/ElementHandleTests/HtmlTableElementTests.cs b/WebView2.DevTools.Dom.Tests/ElementHandleTests/HtmlTableElementTests.cs new file mode 100644 index 0000000..1a1b4d5 --- /dev/null +++ b/WebView2.DevTools.Dom.Tests/ElementHandleTests/HtmlTableElementTests.cs @@ -0,0 +1,214 @@ +using System.Threading.Tasks; +using WebView2.DevTools.Dom.Tests.Attributes; +using Xunit.Abstractions; +using Xunit; + +namespace WebView2.DevTools.Dom.Tests.ElementHandleTests +{ + + [Collection(TestConstants.TestFixtureCollectionName)] + public class HtmlTableElementTests : DevTooolsContextBaseTest + { + public HtmlTableElementTests(ITestOutputHelper output) : base(output) + { + } + + [WebView2ContextFact] + public async Task ShouldWork() + { + await WebView.CoreWebView2.NavigateToAsync(TestConstants.ServerUrl + "/table.html"); + var element = await DevToolsContext.QuerySelectorAsync("table"); + + Assert.NotNull(element); + } + + [WebView2ContextFact] + public async Task ShouldReturnNull() + { + await WebView.CoreWebView2.NavigateToAsync(TestConstants.ServerUrl + "/table.html"); + var element = await DevToolsContext.QuerySelectorAsync("#table2"); + + Assert.Null(element); + } + + [WebView2ContextFact] + public async Task ShouldGetTHead() + { + await WebView.CoreWebView2.NavigateToAsync(TestConstants.ServerUrl + "/table.html"); + var element = await DevToolsContext.QuerySelectorAsync("table"); + + var thead = await element.GetTHeadAsync(); + + Assert.NotNull(thead); + } + + [WebView2ContextFact] + public async Task ShouldCreateTHead() + { + await WebView.CoreWebView2.NavigateToAsync(TestConstants.ServerUrl + "/table.html"); + var element = await DevToolsContext.QuerySelectorAsync("table"); + + var thead = await element.CreateTHeadAsync(); + + Assert.NotNull(thead); + } + + [WebView2ContextFact] + public async Task ShouldGetRowsFromTHead() + { + await WebView.CoreWebView2.NavigateToAsync(TestConstants.ServerUrl + "/table.html"); + var element = await DevToolsContext.QuerySelectorAsync("table"); + + var thead = await element.GetTHeadAsync(); + + Assert.NotNull(thead); + + var rows = await thead.GetRowsAsync(); + + Assert.Equal(1, await rows.GetLengthAsync()); + + await foreach(var row in rows) + { + Assert.Equal("HTMLTableRowElement", row.ClassName); + + await foreach (var cell in await row.GetCellsAsync()) + { + Assert.Equal("HTMLTableCellElement", cell.ClassName); + } + } + } + + [WebView2ContextFact] + public async Task ShouldGetRowsAsArrayFromTHead() + { + await WebView.CoreWebView2.NavigateToAsync(TestConstants.ServerUrl + "/table.html"); + var element = await DevToolsContext.QuerySelectorAsync("table"); + + var thead = await element.GetTHeadAsync(); + + Assert.NotNull(thead); + + var rows = await thead.GetRowsAsync().ToArrayAsync(); + + Assert.Single(rows); + + foreach (var row in rows) + { + Assert.Equal("HTMLTableRowElement", row.ClassName); + + await foreach (var cell in await row.GetCellsAsync()) + { + Assert.Equal("HTMLTableCellElement", cell.ClassName); + } + } + } + + [WebView2ContextFact] + public async Task ShouldGetTFoot() + { + await WebView.CoreWebView2.NavigateToAsync(TestConstants.ServerUrl + "/table.html"); + var element = await DevToolsContext.QuerySelectorAsync("table"); + + var tfoot = await element.GetTFootAsync(); + + Assert.NotNull(tfoot); + } + + [WebView2ContextFact] + public async Task ShouldCreateTFoot() + { + await WebView.CoreWebView2.NavigateToAsync(TestConstants.ServerUrl + "/table.html"); + var element = await DevToolsContext.QuerySelectorAsync("table"); + + var tfoot = await element.CreateTFootAsync(); + + Assert.NotNull(tfoot); + } + + [WebView2ContextFact] + public async Task ShouldGetRowsFromTFoot() + { + await WebView.CoreWebView2.NavigateToAsync(TestConstants.ServerUrl + "/table.html"); + var element = await DevToolsContext.QuerySelectorAsync("table"); + + var tfoot = await element.GetTFootAsync(); + + Assert.NotNull(tfoot); + + var rows = await tfoot.GetRowsAsync(); + + Assert.Equal(1, await rows.GetLengthAsync()); + + await foreach (var row in rows) + { + Assert.Equal("HTMLTableRowElement", row.ClassName); + + await foreach (var cell in await row.GetCellsAsync()) + { + Assert.Equal("HTMLTableCellElement", cell.ClassName); + } + } + } + + [WebView2ContextFact] + public async Task CanAddToTable() + { + await WebView.CoreWebView2.NavigateToAsync(TestConstants.ServerUrl + "/table.html"); + var element = await DevToolsContext.QuerySelectorAsync("table"); + + var rows = await element.GetRowsAsync(); + var rowCount = await rows.GetLengthAsync(); + + var expected = rowCount + 2; + + var newRow1 = await element.InsertRowAsync(); + + var newCell1 = await newRow1.InsertCellAsync(0, "New Cell #1"); + var newCell2 = await newRow1.InsertCellAsync(1, "New Cell #2"); + + Assert.Equal("New Cell #1", await newCell1.GetInnerTextAsync()); + Assert.Equal("New Cell #2", await newCell2.GetInnerTextAsync()); + + var newRow2 = await element.InsertRowAsync(1); + + var newCell3 = await newRow2.InsertCellAsync(0, "New Cell #3"); + var newCell4 = await newRow2.InsertCellAsync(1, "New Cell #4"); + + Assert.Equal("New Cell #3", await newCell3.GetInnerTextAsync()); + Assert.Equal("New Cell #4", await newCell4.GetInnerTextAsync()); + + var actual = await rows.GetLengthAsync(); + + Assert.Equal(expected, actual); + } + + [WebView2ContextFact] + public async Task ShouldGetTBodies() + { + await WebView.CoreWebView2.NavigateToAsync(TestConstants.ServerUrl + "/table.html"); + var element = await DevToolsContext.QuerySelectorAsync("table"); + + var tbodies = await element.GetTBodiesAsync(); + + Assert.NotNull(tbodies); + Assert.IsType>(tbodies); + } + + [WebView2ContextFact] + public async Task ShouldEnumerateTBodies() + { + await WebView.CoreWebView2.NavigateToAsync(TestConstants.ServerUrl + "/table.html"); + var element = await DevToolsContext.QuerySelectorAsync("table"); + + var tbodies = await element.GetTBodiesAsync(); + var length = await tbodies.GetLengthAsync(); + + Assert.Equal(1, length); + + await foreach(var e in tbodies) + { + Assert.IsType(e); + } + } + } +} diff --git a/WebView2.DevTools.Dom.Tests/ElementHandleTests/HtmlTableRowElementTests.cs b/WebView2.DevTools.Dom.Tests/ElementHandleTests/HtmlTableRowElementTests.cs new file mode 100644 index 0000000..b778a66 --- /dev/null +++ b/WebView2.DevTools.Dom.Tests/ElementHandleTests/HtmlTableRowElementTests.cs @@ -0,0 +1,95 @@ +using System.Threading.Tasks; +using WebView2.DevTools.Dom.Tests.Attributes; +using Xunit.Abstractions; +using Xunit; + +namespace WebView2.DevTools.Dom.Tests.ElementHandleTests +{ + + [Collection(TestConstants.TestFixtureCollectionName)] + public class HtmlTableRowElementTests : DevTooolsContextBaseTest + { + public HtmlTableRowElementTests(ITestOutputHelper output) : base(output) + { + } + + [WebView2ContextFact] + public async Task ShouldWork() + { + await WebView.CoreWebView2.NavigateToAsync(TestConstants.ServerUrl + "/table.html"); + var element = await DevToolsContext.QuerySelectorAsync("tr"); + + Assert.NotNull(element); + } + + [WebView2ContextFact] + public async Task ShouldReturnNull() + { + await WebView.CoreWebView2.NavigateToAsync(TestConstants.ServerUrl + "/table.html"); + var element = await DevToolsContext.QuerySelectorAsync("#table2 tr"); + + Assert.Null(element); + } + + [WebView2ContextFact] + public async Task ShouldGetIndex() + { + await WebView.CoreWebView2.NavigateToAsync(TestConstants.ServerUrl + "/table.html"); + var element = await DevToolsContext.QuerySelectorAsync("table").GetBodyAsync(); + + var rows = await element.GetRowsAsync(); + var row = await rows.ItemAsync(0); + + var index = await row.GetRowIndexAsync(); + + Assert.True(index > 0); + } + + [WebView2ContextFact] + public async Task ShouldGetSelectionIndex() + { + await WebView.CoreWebView2.NavigateToAsync(TestConstants.ServerUrl + "/table.html"); + var element = await DevToolsContext.QuerySelectorAsync("table").GetBodyAsync(); + + var rows = await element.GetRowsAsync(); + var row = await rows.ItemAsync(0); + + var index = await row.GetSectionRowIndexAsync(); + + Assert.Equal(0, index); + } + + [WebView2ContextFact] + public async Task ShouldDeleteCell() + { + await WebView.CoreWebView2.NavigateToAsync(TestConstants.ServerUrl + "/table.html"); + var element = await DevToolsContext.QuerySelectorAsync("tr"); + + var cells = await element.GetCellsAsync(); + var expected = await cells.GetLengthAsync() - 1; + + await element.DeleteCellAsync(0); + + var actual = await cells.GetLengthAsync(); + + Assert.Equal(expected, actual); + } + + [WebView2ContextFact] + public async Task ShouldInsertThenDeleteCell() + { + await WebView.CoreWebView2.NavigateToAsync(TestConstants.ServerUrl + "/table.html"); + var element = await DevToolsContext.QuerySelectorAsync("tr"); + + var cell = await element.InsertCellAsync(-1, "Testing"); + + var expected = await element.GetCellsAsync().GetLengthAsync() - 1; + + await element.DeleteCellAsync(cell); + + var actual = await element.GetCellsAsync().GetLengthAsync(); + + Assert.Equal(expected, actual); + } + } +} diff --git a/WebView2.DevTools.Dom.Tests/ElementHandleTests/HtmlTableSectionElementTests.cs b/WebView2.DevTools.Dom.Tests/ElementHandleTests/HtmlTableSectionElementTests.cs new file mode 100644 index 0000000..8547f39 --- /dev/null +++ b/WebView2.DevTools.Dom.Tests/ElementHandleTests/HtmlTableSectionElementTests.cs @@ -0,0 +1,80 @@ +using System.Threading.Tasks; +using WebView2.DevTools.Dom.Tests.Attributes; +using Xunit.Abstractions; +using Xunit; + +namespace WebView2.DevTools.Dom.Tests.ElementHandleTests +{ + + [Collection(TestConstants.TestFixtureCollectionName)] + public class HtmlTableSectionElementTests : DevTooolsContextBaseTest + { + public HtmlTableSectionElementTests(ITestOutputHelper output) : base(output) + { + } + + [WebView2ContextFact] + public async Task ShouldWork() + { + await WebView.CoreWebView2.NavigateToAsync(TestConstants.ServerUrl + "/table.html"); + var element = await DevToolsContext.QuerySelectorAsync("table").GetBodyAsync(); + + Assert.NotNull(element); + } + + [WebView2ContextFact] + public async Task ShouldReturnNull() + { + await WebView.CoreWebView2.NavigateToAsync(TestConstants.ServerUrl + "/table.html"); + var element = await DevToolsContext.QuerySelectorAsync("#table2").GetBodyAsync(); + + Assert.Null(element); + } + + [WebView2ContextFact] + public async Task ShouldInsertRow() + { + await WebView.CoreWebView2.NavigateToAsync(TestConstants.ServerUrl + "/table.html"); + var element = await DevToolsContext.QuerySelectorAsync("table").GetBodyAsync(); + + var row = await element.InsertRowAsync(-1); + + Assert.NotNull(row); + } + + [WebView2ContextFact] + public async Task ShouldDeleteRow() + { + await WebView.CoreWebView2.NavigateToAsync(TestConstants.ServerUrl + "/table.html"); + var element = await DevToolsContext.QuerySelectorAsync("table").GetBodyAsync(); + + var initialLength = await element.GetRowsAsync().GetLengthAsync(); + var expected = initialLength - 1; + + await element.DeleteRowAsync(0); + + var actual = await element.GetRowsAsync().GetLengthAsync(); + + Assert.Equal(expected, actual); + } + + [WebView2ContextFact] + public async Task ShouldInsertThenDeleteRow() + { + await WebView.CoreWebView2.NavigateToAsync(TestConstants.ServerUrl + "/table.html"); + var element = await DevToolsContext.QuerySelectorAsync("table").GetBodyAsync(); + + var expected = await element.GetRowsAsync().GetLengthAsync(); + + var row = await element.InsertRowAsync(-1); + + var rowIndex = await row.GetSectionRowIndexAsync(); + + await element.DeleteRowAsync(rowIndex); + + var actual = await element.GetRowsAsync().GetLengthAsync(); + + Assert.Equal(expected, actual); + } + } +} diff --git a/WebView2.DevTools.Dom.Tests/JSHandleTests/DevToolsContextEvaluateHandle.cs b/WebView2.DevTools.Dom.Tests/JSHandleTests/DevToolsContextEvaluateHandle.cs index d17b5ab..1813169 100644 --- a/WebView2.DevTools.Dom.Tests/JSHandleTests/DevToolsContextEvaluateHandle.cs +++ b/WebView2.DevTools.Dom.Tests/JSHandleTests/DevToolsContextEvaluateHandle.cs @@ -1,5 +1,4 @@ using System.Threading.Tasks; -using WebView2.DevTools.Dom; using WebView2.DevTools.Dom.Tests.Attributes; using Xunit; using Xunit.Abstractions; diff --git a/WebView2.DevTools.Dom.Tests/KeyboardTests/KeyboardTests.cs b/WebView2.DevTools.Dom.Tests/KeyboardTests/KeyboardTests.cs index 6470c81..8e055c1 100644 --- a/WebView2.DevTools.Dom.Tests/KeyboardTests/KeyboardTests.cs +++ b/WebView2.DevTools.Dom.Tests/KeyboardTests/KeyboardTests.cs @@ -52,24 +52,32 @@ public async Task ShouldMoveWithTheArrowKeys() [WebView2ContextFact] public async Task ShouldSendACharacterWithElementHandlePress() { + const string expected = "a"; + await WebView.CoreWebView2.NavigateToAsync(TestConstants.ServerUrl + "/input/textarea.html"); - var textarea = await DevToolsContext.QuerySelectorAsync("textarea"); - await textarea.PressAsync("a"); - Assert.Equal("a", await DevToolsContext.EvaluateExpressionAsync("document.querySelector('textarea').value")); + var textarea = await DevToolsContext.QuerySelectorAsync("textarea"); + await textarea.PressAsync(expected); + + var actual = await textarea.GetValueAsync(); + + Assert.Equal(expected, actual); await DevToolsContext.EvaluateExpressionAsync("window.addEventListener('keydown', e => e.preventDefault(), true)"); await textarea.PressAsync("b"); - Assert.Equal("a", await DevToolsContext.EvaluateExpressionAsync("document.querySelector('textarea').value")); + + actual = await textarea.GetValueAsync(); + + Assert.Equal(expected, actual); } [WebView2ContextFact] public async Task ElementHandlePressShouldSupportTextOption() { await WebView.CoreWebView2.NavigateToAsync(TestConstants.ServerUrl + "/input/textarea.html"); - var textarea = await DevToolsContext.QuerySelectorAsync("textarea"); + var textarea = await DevToolsContext.QuerySelectorAsync("textarea"); await textarea.PressAsync("a", new PressOptions { Text = "ё" }); - var actual = await DevToolsContext.EvaluateExpressionAsync("document.querySelector('textarea').value"); + var actual = await textarea.GetValueAsync(); Assert.Equal("ё", actual); } @@ -186,6 +194,7 @@ await DevToolsContext.EvaluateExpressionAsync(@"{ public async Task ShouldSpecifyRepeatProperty() { await WebView.CoreWebView2.NavigateToAsync(TestConstants.ServerUrl + "/input/textarea.html"); + await DevToolsContext.FocusAsync("textarea"); await DevToolsContext.EvaluateExpressionAsync("document.querySelector('textarea').addEventListener('keydown', e => window.lastEvent = e, true)"); await DevToolsContext.Keyboard.DownAsync("a"); @@ -199,13 +208,20 @@ public async Task ShouldSpecifyRepeatProperty() Assert.True(expected); await DevToolsContext.Keyboard.DownAsync("b"); - Assert.False(await DevToolsContext.EvaluateExpressionAsync("window.lastEvent.repeat")); + + expected = await DevToolsContext.EvaluateExpressionAsync("window.lastEvent.repeat"); + Assert.False(expected); await DevToolsContext.Keyboard.DownAsync("b"); - Assert.True(await DevToolsContext.EvaluateExpressionAsync("window.lastEvent.repeat")); + + expected = await DevToolsContext.EvaluateExpressionAsync("window.lastEvent.repeat"); + Assert.True(expected); await DevToolsContext.Keyboard.UpAsync("a"); await DevToolsContext.Keyboard.DownAsync("a"); - Assert.False(await DevToolsContext.EvaluateExpressionAsync("window.lastEvent.repeat")); + + expected = await DevToolsContext.EvaluateExpressionAsync("window.lastEvent.repeat"); + + Assert.False(expected); } [WebView2ContextFact] @@ -225,7 +241,7 @@ public async Task ShouldSpecifyLocation() await DevToolsContext.EvaluateExpressionAsync(@"{ window.addEventListener('keydown', event => window.keyLocation = event.location, true); }"); - var textarea = await DevToolsContext.QuerySelectorAsync("textarea"); + var textarea = await DevToolsContext.QuerySelectorAsync("textarea"); await textarea.PressAsync("Digit5"); Assert.Equal(0, await DevToolsContext.EvaluateExpressionAsync("keyLocation")); @@ -266,7 +282,7 @@ public async Task ShouldTypeEmojiIntoAniframe() await WebView.CoreWebView2.NavigateToAsync(TestConstants.EmptyPage); await FrameUtils.AttachFrameAsync(DevToolsContext, "emoji-test", TestConstants.ServerUrl + "/input/textarea.html"); var frame = DevToolsContext.FirstChildFrame(); - var textarea = await frame.QuerySelectorAsync("textarea"); + var textarea = await frame.QuerySelectorAsync("textarea"); await textarea.TypeAsync("👹 Tokyo street Japan \uD83C\uDDEF\uD83C\uDDF5"); Assert.Equal( "👹 Tokyo street Japan \uD83C\uDDEF\uD83C\uDDF5", diff --git a/WebView2.DevTools.Dom.Tests/MouseTests/MouseTests.cs b/WebView2.DevTools.Dom.Tests/MouseTests/MouseTests.cs index 3a8c4a6..c672d9b 100644 --- a/WebView2.DevTools.Dom.Tests/MouseTests/MouseTests.cs +++ b/WebView2.DevTools.Dom.Tests/MouseTests/MouseTests.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Threading.Tasks; -using WebView2.DevTools.Dom; using WebView2.DevTools.Dom.Input; using WebView2.DevTools.Dom.Tests.Attributes; using Xunit; @@ -12,6 +11,8 @@ namespace WebView2.DevTools.Dom.Tests.MouseTests [Collection(TestConstants.TestFixtureCollectionName)] public class MouseTests : DevTooolsContextBaseTest { + private readonly ITestOutputHelper _testOutputHelper; + private const string Dimensions = @"function dimensions() { const rect = document.querySelector('textarea').getBoundingClientRect(); return { @@ -24,6 +25,7 @@ public class MouseTests : DevTooolsContextBaseTest public MouseTests(ITestOutputHelper output) : base(output) { + _testOutputHelper = output; } [WebView2ContextFact] @@ -58,6 +60,7 @@ await DevToolsContext.EvaluateFunctionAsync(@"() => { public async Task ShouldResizeTheTextarea() { await WebView.CoreWebView2.NavigateToAsync(TestConstants.ServerUrl + "/input/textarea.html"); + var dimensions = await DevToolsContext.EvaluateFunctionAsync(Dimensions); var mouse = DevToolsContext.Mouse; await mouse.MoveAsync(dimensions.X + dimensions.Width - 4, dimensions.Y + dimensions.Height - 4); @@ -72,9 +75,11 @@ public async Task ShouldResizeTheTextarea() [WebView2ContextFact] public async Task ShouldSelectTheTextWithMouse() { + const string expectedText = "This is the text that we are going to try to select. Let's see how it goes."; + await WebView.CoreWebView2.NavigateToAsync(TestConstants.ServerUrl + "/input/textarea.html"); await DevToolsContext.FocusAsync("textarea"); - const string expectedText = "This is the text that we are going to try to select. Let's see how it goes."; + await DevToolsContext.Keyboard.TypeAsync(expectedText); await DevToolsContext.EvaluateExpressionAsync("document.querySelector('textarea').scrollTop = 0"); var dimensions = await DevToolsContext.EvaluateFunctionAsync(Dimensions); diff --git a/WebView2.DevTools.Dom.Tests/QuerySelectorTests/DevToolsContextQuerySelectorAllTests.cs b/WebView2.DevTools.Dom.Tests/QuerySelectorTests/DevToolsContextQuerySelectorAllTests.cs index 4f64932..b4e93de 100644 --- a/WebView2.DevTools.Dom.Tests/QuerySelectorTests/DevToolsContextQuerySelectorAllTests.cs +++ b/WebView2.DevTools.Dom.Tests/QuerySelectorTests/DevToolsContextQuerySelectorAllTests.cs @@ -13,6 +13,26 @@ public DevToolsContextQuerySelectorAllTests(ITestOutputHelper output) : base(out { } + [WebView2ContextFact] + public async Task ShouldWork() + { + await WebView.CoreWebView2.NavigateToAsync(TestConstants.ServerUrl + "/table.html"); + var elements = await DevToolsContext.QuerySelectorAllAsync("tr"); + + Assert.NotNull(elements); + Assert.Equal(4, elements.Length); + } + + [WebView2ContextFact] + public async Task ShouldReturnEmptyArray() + { + await WebView.CoreWebView2.NavigateToAsync(TestConstants.ServerUrl + "/table.html"); + var elements = await DevToolsContext.QuerySelectorAllAsync("#table2 tr"); + + Assert.NotNull(elements); + Assert.Empty(elements); + } + [WebView2ContextFact] public async Task ShouldQueryExistingElements() { diff --git a/WebView2.DevTools.Dom.Tests/QuerySelectorTests/DevToolsContextQuerySelectorTests.cs b/WebView2.DevTools.Dom.Tests/QuerySelectorTests/DevToolsContextQuerySelectorTests.cs index 75386b5..7683ce4 100644 --- a/WebView2.DevTools.Dom.Tests/QuerySelectorTests/DevToolsContextQuerySelectorTests.cs +++ b/WebView2.DevTools.Dom.Tests/QuerySelectorTests/DevToolsContextQuerySelectorTests.cs @@ -47,6 +47,7 @@ void Usage(CoreWebView2 coreWebView2) var htmlTextAreaElement = await devToolsContext.QuerySelectorAsync("#myTextAreaElementId"); var htmlButtonElement = await devToolsContext.QuerySelectorAsync("#myButtonElementId"); var htmlParagraphElement = await devToolsContext.QuerySelectorAsync("#myParagraphElementId"); + var htmlTableElement = await devToolsContext.QuerySelectorAsync("#myTableElementId"); // Get a custom attribute value var customAttribute = await element.GetAttributeAsync("data-customAttribute"); @@ -93,7 +94,7 @@ await devToolsContext.ExposeFunctionAsync("jsAlertButtonClick", () => _ = jsAlertButton.AddEventListenerAsync("click", "jsAlertButtonClick"); //Get a collection of HtmlElements - var divElements = await devToolsContext.QuerySelectorAllAsync("div"); + var divElements = await devToolsContext.QuerySelectorAllAsync("div"); foreach (var div in divElements) { @@ -106,6 +107,35 @@ await devToolsContext.ExposeFunctionAsync("jsAlertButtonClick", () => await div.SetAttributeAsync("data-customAttribute", "123"); await div.SetInnerTextAsync("Updated Div innerText"); } + + //Using standard array + var tableRows = await htmlTableElement.GetRowsAsync().ToArrayAsync(); + + foreach(var row in tableRows) + { + var cells = await row.GetCellsAsync().ToArrayAsync(); + foreach(var cell in cells) + { + var newDiv = await devToolsContext.CreateHtmlElementAsync("div"); + await newDiv.SetInnerTextAsync("New Div Added!"); + await cell.AppendChildAsync(newDiv); + } + } + + //Get a reference to the HtmlCollection and use async enumerable + //Requires Net Core 3.1 or higher + var tableRowsHtmlCollection = await htmlTableElement.GetRowsAsync(); + + await foreach (var row in tableRowsHtmlCollection) + { + var cells = await row.GetCellsAsync(); + await foreach (var cell in cells) + { + var newDiv = await devToolsContext.CreateHtmlElementAsync("div"); + await newDiv.SetInnerTextAsync("New Div Added!"); + await cell.AppendChildAsync(newDiv); + } + } } }; diff --git a/WebView2.DevTools.Dom.Tests/TestServer/wwwroot/table.html b/WebView2.DevTools.Dom.Tests/TestServer/wwwroot/table.html new file mode 100644 index 0000000..50a5e41 --- /dev/null +++ b/WebView2.DevTools.Dom.Tests/TestServer/wwwroot/table.html @@ -0,0 +1,34 @@ + + + + + WebView 2 Table Testing + + +

Table Testing

+ + + + + + + + + + + + + + + + + + + + + + + +
Header #1Header #2
Row #1 - Cell #1Row #1 - Cell #2
Row #2 - Cell #1Row #2 - Cell #2
Footer #1Footer #2
+ + diff --git a/WebView2.DevTools.Dom.Tests/WaitTaskTests/FrameWaitForFunctionTests.cs b/WebView2.DevTools.Dom.Tests/WaitTaskTests/FrameWaitForFunctionTests.cs index a379706..17ab659 100644 --- a/WebView2.DevTools.Dom.Tests/WaitTaskTests/FrameWaitForFunctionTests.cs +++ b/WebView2.DevTools.Dom.Tests/WaitTaskTests/FrameWaitForFunctionTests.cs @@ -1,6 +1,5 @@ using System; using System.Threading.Tasks; -using WebView2.DevTools.Dom; using WebView2.DevTools.Dom.Tests.Attributes; using Xunit; using Xunit.Abstractions; @@ -36,7 +35,11 @@ public async Task ShouldPollOnInterval() .ContinueWith(_ => success = true); await DevToolsContext.EvaluateExpressionAsync("window.__FOO = 'hit'"); Assert.False(success); - await DevToolsContext.EvaluateExpressionAsync("document.body.appendChild(document.createElement('div'))"); + + var div = await DevToolsContext.CreateHtmlElementAsync("div"); + + await DevToolsContext.AppendChildAsync(div); + await watchdog; Assert.True((DateTime.Now - startTime).TotalMilliseconds > polling / 2); } diff --git a/WebView2.DevTools.Dom.Tests/WebView2.DevTools.Dom.Tests.csproj b/WebView2.DevTools.Dom.Tests/WebView2.DevTools.Dom.Tests.csproj index 0ac8dff..a7d0ccc 100644 --- a/WebView2.DevTools.Dom.Tests/WebView2.DevTools.Dom.Tests.csproj +++ b/WebView2.DevTools.Dom.Tests/WebView2.DevTools.Dom.Tests.csproj @@ -15,7 +15,7 @@ - +