diff --git a/CHANGELOG.md b/CHANGELOG.md index bf6a90b80..a09b7a5b5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,12 @@ All notable changes to **bUnit** will be documented in this file. The project ad ## [Unreleased] +### Added +- Added `FindByAllByLabel` to `bunit.web.query` package. By [@linkdotnet](https://github.com/linkdotnet). + +### Fixed +- Updated `AngleSharp.Diffing` to fix a bug related to unknown HTML elements. Reported by [@md-at-slashwhy](https://github.com/md-at-slashwhy). + ## [2.1.1] - 2025-11-21 ### Changed diff --git a/Directory.Packages.props b/Directory.Packages.props index 73e40e4e4..d99488398 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -6,9 +6,9 @@ - + - + @@ -17,8 +17,8 @@ - - + + @@ -81,18 +81,18 @@ - + - + - - - + + + diff --git a/bunit.sln b/bunit.sln deleted file mode 100644 index e5b5294d4..000000000 --- a/bunit.sln +++ /dev/null @@ -1,123 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 -VisualStudioVersion = 17.0.31710.8 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".items", ".items", "{A5D7B605-02D8-468C-9BDF-864CF93B12F9}" - ProjectSection(SolutionItems) = preProject - .editorconfig = .editorconfig - .gitattributes = .gitattributes - .gitignore = .gitignore - Directory.Build.props = Directory.Build.props - Directory.Packages.props = Directory.Packages.props - .config\dotnet-tools.json = .config\dotnet-tools.json - global.json = global.json - version.json = version.json - EndProjectSection -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{9A2B3B34-D41C-43E8-BC7D-246BEBE48D59}" - ProjectSection(SolutionItems) = preProject - src\.editorconfig = src\.editorconfig - src\Directory.Build.props = src\Directory.Build.props - EndProjectSection -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{6EA09ED4-B714-4E6F-B0E1-4D987F8AE520}" - ProjectSection(SolutionItems) = preProject - tests\.editorconfig = tests\.editorconfig - tests\Directory.Build.props = tests\Directory.Build.props - tests\run-tests.ps1 = tests\run-tests.ps1 - tests\xunit.runner.json = tests\xunit.runner.json - EndProjectSection -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".text", ".text", "{392FCD4E-356A-412A-A854-8EE197EA65B9}" - ProjectSection(SolutionItems) = preProject - CHANGELOG.md = CHANGELOG.md - README.md = README.md - MIGRATION.md = MIGRATION.md - EndProjectSection -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "bunit", "src\bunit\bunit.csproj", "{1DA6EFDE-81A1-4324-A56C-40BEE14A75BA}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "bunit.template", "src\bunit.template\bunit.template.csproj", "{6127D121-9387-451B-B15D-8350A32D3001}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "bunit.testassets", "tests\bunit.testassets\bunit.testassets.csproj", "{7972A80F-30DC-4EF4-9294-7D4DD2965882}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".workflows", ".workflows", "{3B2F3419-5336-4147-A212-E19091195203}" - ProjectSection(SolutionItems) = preProject - .github\workflows\ci.yml = .github\workflows\ci.yml - .github\workflows\docs-deploy.yml = .github\workflows\docs-deploy.yml - .github\workflows\prepare-release.yml = .github\workflows\prepare-release.yml - .github\workflows\release.yml = .github\workflows\release.yml - EndProjectSection -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "bunit.web.query", "src\bunit.web.query\bunit.web.query.csproj", "{0FF92169-7D8F-46A2-8327-A2F028CB426F}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "bunit.web.query.tests", "tests\bunit.web.query.tests\bunit.web.query.tests.csproj", "{DE975A0C-0672-4248-913E-D267C1001801}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "bunit.generators.internal", "src\bunit.generators.internal\bunit.generators.internal.csproj", "{AE3DFB52-2BF4-4806-AD82-7FB7B38AC17F}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "bunit.generators", "src\bunit.generators\bunit.generators.csproj", "{A7C6A2AA-FF8F-4ED1-8590-5324FC566059}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "bunit.tests", "tests\bunit.tests\bunit.tests.csproj", "{56889DE7-5E66-4E9C-815B-CBCFC9961612}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "bunit.generators.tests", "tests\bunit.generators.tests\bunit.generators.tests.csproj", "{D08F7F1D-74B1-4A76-86A2-94918863740C}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {1DA6EFDE-81A1-4324-A56C-40BEE14A75BA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {1DA6EFDE-81A1-4324-A56C-40BEE14A75BA}.Release|Any CPU.ActiveCfg = Release|Any CPU - {1DA6EFDE-81A1-4324-A56C-40BEE14A75BA}.Release|Any CPU.Build.0 = Release|Any CPU - {1DA6EFDE-81A1-4324-A56C-40BEE14A75BA}.Debug|Any CPU.Build.0 = Debug|Any CPU - {6127D121-9387-451B-B15D-8350A32D3001}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {6127D121-9387-451B-B15D-8350A32D3001}.Release|Any CPU.ActiveCfg = Release|Any CPU - {7972A80F-30DC-4EF4-9294-7D4DD2965882}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {7972A80F-30DC-4EF4-9294-7D4DD2965882}.Debug|Any CPU.Build.0 = Debug|Any CPU - {7972A80F-30DC-4EF4-9294-7D4DD2965882}.Release|Any CPU.ActiveCfg = Release|Any CPU - {7972A80F-30DC-4EF4-9294-7D4DD2965882}.Release|Any CPU.Build.0 = Release|Any CPU - {0FF92169-7D8F-46A2-8327-A2F028CB426F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {0FF92169-7D8F-46A2-8327-A2F028CB426F}.Debug|Any CPU.Build.0 = Debug|Any CPU - {0FF92169-7D8F-46A2-8327-A2F028CB426F}.Release|Any CPU.ActiveCfg = Release|Any CPU - {0FF92169-7D8F-46A2-8327-A2F028CB426F}.Release|Any CPU.Build.0 = Release|Any CPU - {DE975A0C-0672-4248-913E-D267C1001801}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {DE975A0C-0672-4248-913E-D267C1001801}.Debug|Any CPU.Build.0 = Debug|Any CPU - {DE975A0C-0672-4248-913E-D267C1001801}.Release|Any CPU.ActiveCfg = Release|Any CPU - {DE975A0C-0672-4248-913E-D267C1001801}.Release|Any CPU.Build.0 = Release|Any CPU - {AE3DFB52-2BF4-4806-AD82-7FB7B38AC17F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {AE3DFB52-2BF4-4806-AD82-7FB7B38AC17F}.Debug|Any CPU.Build.0 = Debug|Any CPU - {AE3DFB52-2BF4-4806-AD82-7FB7B38AC17F}.Release|Any CPU.ActiveCfg = Release|Any CPU - {AE3DFB52-2BF4-4806-AD82-7FB7B38AC17F}.Release|Any CPU.Build.0 = Release|Any CPU - {A7C6A2AA-FF8F-4ED1-8590-5324FC566059}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {A7C6A2AA-FF8F-4ED1-8590-5324FC566059}.Debug|Any CPU.Build.0 = Debug|Any CPU - {A7C6A2AA-FF8F-4ED1-8590-5324FC566059}.Release|Any CPU.ActiveCfg = Release|Any CPU - {A7C6A2AA-FF8F-4ED1-8590-5324FC566059}.Release|Any CPU.Build.0 = Release|Any CPU - {56889DE7-5E66-4E9C-815B-CBCFC9961612}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {56889DE7-5E66-4E9C-815B-CBCFC9961612}.Debug|Any CPU.Build.0 = Debug|Any CPU - {56889DE7-5E66-4E9C-815B-CBCFC9961612}.Release|Any CPU.ActiveCfg = Release|Any CPU - {56889DE7-5E66-4E9C-815B-CBCFC9961612}.Release|Any CPU.Build.0 = Release|Any CPU - {D08F7F1D-74B1-4A76-86A2-94918863740C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D08F7F1D-74B1-4A76-86A2-94918863740C}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D08F7F1D-74B1-4A76-86A2-94918863740C}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D08F7F1D-74B1-4A76-86A2-94918863740C}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(NestedProjects) = preSolution - {1DA6EFDE-81A1-4324-A56C-40BEE14A75BA} = {9A2B3B34-D41C-43E8-BC7D-246BEBE48D59} - {6127D121-9387-451B-B15D-8350A32D3001} = {9A2B3B34-D41C-43E8-BC7D-246BEBE48D59} - {7972A80F-30DC-4EF4-9294-7D4DD2965882} = {6EA09ED4-B714-4E6F-B0E1-4D987F8AE520} - {0FF92169-7D8F-46A2-8327-A2F028CB426F} = {9A2B3B34-D41C-43E8-BC7D-246BEBE48D59} - {DE975A0C-0672-4248-913E-D267C1001801} = {6EA09ED4-B714-4E6F-B0E1-4D987F8AE520} - {AE3DFB52-2BF4-4806-AD82-7FB7B38AC17F} = {9A2B3B34-D41C-43E8-BC7D-246BEBE48D59} - {A7C6A2AA-FF8F-4ED1-8590-5324FC566059} = {9A2B3B34-D41C-43E8-BC7D-246BEBE48D59} - {56889DE7-5E66-4E9C-815B-CBCFC9961612} = {6EA09ED4-B714-4E6F-B0E1-4D987F8AE520} - {D08F7F1D-74B1-4A76-86A2-94918863740C} = {6EA09ED4-B714-4E6F-B0E1-4D987F8AE520} - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {24106918-1C86-4769-BDA6-9C80E64CD260} - EndGlobalSection -EndGlobal diff --git a/bunit.slnx b/bunit.slnx new file mode 100644 index 000000000..7294d3ede --- /dev/null +++ b/bunit.slnx @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/README.md b/docs/README.md index 5baf50e7a..0568e6f0d 100644 --- a/docs/README.md +++ b/docs/README.md @@ -28,7 +28,7 @@ The following tools are required to build and view the documentation locally: ### View the documentation -1. Build the `bunit.sln` solution in the root folder in release configuration `dotnet build -c Release`. +1. Build the `bunit.slxn` solution in the root folder in release configuration `dotnet build -c Release`. 2. From `docs/site` run `docfx metadata` to generate the documentation site's metadata. 3. After that run `docfx build` to generate the documentation site. 4. From `docs/` run `serve-docs.cmd`. This will start up a local web server (using `dotnet serve`), hosting the generated documentation site. diff --git a/src/bunit.web.query/Labels/LabelQueryExtensions.cs b/src/bunit.web.query/Labels/LabelQueryExtensions.cs index d388f7bf7..b4639cb4f 100644 --- a/src/bunit.web.query/Labels/LabelQueryExtensions.cs +++ b/src/bunit.web.query/Labels/LabelQueryExtensions.cs @@ -1,5 +1,6 @@ using AngleSharp.Dom; using Bunit.Labels.Strategies; +using Bunit.Web.AngleSharp; namespace Bunit; @@ -35,6 +36,25 @@ public static IElement FindByLabelText(this IRenderedComponent rende return FindByLabelTextInternal(renderedComponent, labelText, options) ?? throw new LabelNotFoundException(labelText); } + /// + /// Returns all elements (i.e. input, select, textarea, etc. elements) associated with the given label text. + /// + /// The rendered fragment to search. + /// The text of the label to search (i.e. the InnerText of the Label, such as "First Name" for a ``) + /// Method used to override the default behavior of FindAllByLabelText. + /// A read-only collection of elements matching the label text. Returns an empty collection if no matches are found. + public static IReadOnlyList FindAllByLabelText(this IRenderedComponent renderedComponent, string labelText, Action? configureOptions = null) + { + var options = ByLabelTextOptions.Default; + if (configureOptions is not null) + { + options = options with { }; + configureOptions.Invoke(options); + } + + return FindAllByLabelTextInternal(renderedComponent, labelText, options); + } + internal static IElement? FindByLabelTextInternal(this IRenderedComponent renderedComponent, string labelText, ByLabelTextOptions options) { foreach (var strategy in LabelTextQueryStrategies) @@ -47,4 +67,28 @@ public static IElement FindByLabelText(this IRenderedComponent rende return null; } + + internal static IReadOnlyList FindAllByLabelTextInternal(this IRenderedComponent renderedComponent, string labelText, ByLabelTextOptions options) + { + var results = new List(); + + foreach (var strategy in LabelTextQueryStrategies) + { + results.AddRange(strategy.FindElements(renderedComponent, labelText, options)); + } + + var seen = new HashSet(); + var distinctResults = new List(); + + foreach (var element in results) + { + var underlyingElement = element.Unwrap(); + if (seen.Add(underlyingElement)) + { + distinctResults.Add(element); + } + } + + return distinctResults; + } } diff --git a/src/bunit.web.query/Labels/Strategies/ILabelTextQueryStrategy.cs b/src/bunit.web.query/Labels/Strategies/ILabelTextQueryStrategy.cs index 0477c79f4..d53385591 100644 --- a/src/bunit.web.query/Labels/Strategies/ILabelTextQueryStrategy.cs +++ b/src/bunit.web.query/Labels/Strategies/ILabelTextQueryStrategy.cs @@ -4,5 +4,8 @@ namespace Bunit.Labels.Strategies; internal interface ILabelTextQueryStrategy { - IElement? FindElement(IRenderedComponent renderedComponent, string labelText, ByLabelTextOptions options); + IElement? FindElement(IRenderedComponent renderedComponent, string labelText, ByLabelTextOptions options) + => FindElements(renderedComponent, labelText, options).FirstOrDefault(); + + IEnumerable FindElements(IRenderedComponent renderedComponent, string labelText, ByLabelTextOptions options); } diff --git a/src/bunit.web.query/Labels/Strategies/LabelTextUsingAriaLabelStrategy.cs b/src/bunit.web.query/Labels/Strategies/LabelTextUsingAriaLabelStrategy.cs index e2c0a4329..771ada084 100644 --- a/src/bunit.web.query/Labels/Strategies/LabelTextUsingAriaLabelStrategy.cs +++ b/src/bunit.web.query/Labels/Strategies/LabelTextUsingAriaLabelStrategy.cs @@ -5,7 +5,7 @@ namespace Bunit.Labels.Strategies; internal sealed class LabelTextUsingAriaLabelStrategy : ILabelTextQueryStrategy { - public IElement? FindElement(IRenderedComponent renderedComponent, string labelText, ByLabelTextOptions options) + public IEnumerable FindElements(IRenderedComponent renderedComponent, string labelText, ByLabelTextOptions options) { var caseSensitivityQualifier = options.ComparisonType switch { @@ -15,11 +15,11 @@ internal sealed class LabelTextUsingAriaLabelStrategy : ILabelTextQueryStrategy _ => "" }; - var element = renderedComponent.Nodes.TryQuerySelector($"[aria-label='{labelText}'{caseSensitivityQualifier}]"); + var elements = renderedComponent.Nodes.TryQuerySelectorAll($"[aria-label='{labelText}'{caseSensitivityQualifier}]"); - if (element is null) - return null; - - return element.WrapUsing(new ByLabelTextElementFactory(renderedComponent, labelText, options)); + foreach (var element in elements) + { + yield return element.WrapUsing(new ByLabelTextElementFactory(renderedComponent, labelText, options)); + } } } diff --git a/src/bunit.web.query/Labels/Strategies/LabelTextUsingAriaLabelledByStrategy.cs b/src/bunit.web.query/Labels/Strategies/LabelTextUsingAriaLabelledByStrategy.cs index 36108d892..f8f5ab87c 100644 --- a/src/bunit.web.query/Labels/Strategies/LabelTextUsingAriaLabelledByStrategy.cs +++ b/src/bunit.web.query/Labels/Strategies/LabelTextUsingAriaLabelledByStrategy.cs @@ -5,7 +5,7 @@ namespace Bunit.Labels.Strategies; internal sealed class LabelTextUsingAriaLabelledByStrategy : ILabelTextQueryStrategy { - public IElement? FindElement(IRenderedComponent renderedComponent, string labelText, ByLabelTextOptions options) + public IEnumerable FindElements(IRenderedComponent renderedComponent, string labelText, ByLabelTextOptions options) { var elementsWithAriaLabelledBy = renderedComponent.Nodes.TryQuerySelectorAll("[aria-labelledby]"); @@ -13,9 +13,7 @@ internal sealed class LabelTextUsingAriaLabelledByStrategy : ILabelTextQueryStra { var labelElement = renderedComponent.Nodes.TryQuerySelector($"#{element.GetAttribute("aria-labelledby")}"); if (labelElement is not null && labelElement.GetInnerText().Equals(labelText, options.ComparisonType)) - return element.WrapUsing(new ByLabelTextElementFactory(renderedComponent, labelText, options)); + yield return element.WrapUsing(new ByLabelTextElementFactory(renderedComponent, labelText, options)); } - - return null; } } diff --git a/src/bunit.web.query/Labels/Strategies/LabelTextUsingForAttributeStrategy.cs b/src/bunit.web.query/Labels/Strategies/LabelTextUsingForAttributeStrategy.cs index d9577032a..2ab1931bf 100644 --- a/src/bunit.web.query/Labels/Strategies/LabelTextUsingForAttributeStrategy.cs +++ b/src/bunit.web.query/Labels/Strategies/LabelTextUsingForAttributeStrategy.cs @@ -5,19 +5,20 @@ namespace Bunit.Labels.Strategies; internal sealed class LabelTextUsingForAttributeStrategy : ILabelTextQueryStrategy { - public IElement? FindElement(IRenderedComponent renderedComponent, string labelText, ByLabelTextOptions options) + public IEnumerable FindElements(IRenderedComponent renderedComponent, string labelText, ByLabelTextOptions options) { - var matchingLabel = renderedComponent.Nodes.TryQuerySelectorAll("label") - .SingleOrDefault(l => l.TextContent.Trim().Equals(labelText, options.ComparisonType)); + var matchingLabels = renderedComponent.Nodes.TryQuerySelectorAll("label") + .Where(l => l.TextContent.Trim().Equals(labelText, options.ComparisonType)); - if (matchingLabel is null) - return null; + foreach (var matchingLabel in matchingLabels) + { + var forAttribute = matchingLabel.GetAttribute("for"); + if (string.IsNullOrEmpty(forAttribute)) + continue; - var matchingElement = renderedComponent.Nodes.TryQuerySelector($"#{matchingLabel.GetAttribute("for")}"); - - if (matchingElement is null) - return null; - - return matchingElement.WrapUsing(new ByLabelTextElementFactory(renderedComponent, labelText, options)); + var matchingElement = renderedComponent.Nodes.TryQuerySelector($"#{forAttribute}"); + if (matchingElement is not null) + yield return matchingElement.WrapUsing(new ByLabelTextElementFactory(renderedComponent, labelText, options)); + } } } diff --git a/src/bunit.web.query/Labels/Strategies/LabelTextUsingWrappedElementStrategy.cs b/src/bunit.web.query/Labels/Strategies/LabelTextUsingWrappedElementStrategy.cs index ca2afb9c8..e503c92cc 100644 --- a/src/bunit.web.query/Labels/Strategies/LabelTextUsingWrappedElementStrategy.cs +++ b/src/bunit.web.query/Labels/Strategies/LabelTextUsingWrappedElementStrategy.cs @@ -5,15 +5,18 @@ namespace Bunit.Labels.Strategies; internal sealed class LabelTextUsingWrappedElementStrategy : ILabelTextQueryStrategy { - public IElement? FindElement(IRenderedComponent renderedComponent, string labelText, ByLabelTextOptions options) + public IEnumerable FindElements(IRenderedComponent renderedComponent, string labelText, ByLabelTextOptions options) { - var matchingLabel = renderedComponent.Nodes.TryQuerySelectorAll("label") - .SingleOrDefault(l => l.GetInnerText().Trim().StartsWith(labelText, options.ComparisonType)); + var matchingLabels = renderedComponent.Nodes.TryQuerySelectorAll("label") + .Where(l => l.GetInnerText().Trim().StartsWith(labelText, options.ComparisonType)); - var matchingElement = matchingLabel? - .Children - .SingleOrDefault(n => n.IsHtmlElementThatCanHaveALabel()); - - return matchingElement?.WrapUsing(new ByLabelTextElementFactory(renderedComponent, labelText, options)); + foreach (var matchingLabel in matchingLabels) + { + var matchingElements = matchingLabel.Children.Where(n => n.IsHtmlElementThatCanHaveALabel()); + foreach (var matchingElement in matchingElements) + { + yield return matchingElement.WrapUsing(new ByLabelTextElementFactory(renderedComponent, labelText, options)); + } + } } } diff --git a/src/bunit/InternalsVisibleTo.cs b/src/bunit/InternalsVisibleTo.cs index a3c9cf4b0..6bdae613c 100644 --- a/src/bunit/InternalsVisibleTo.cs +++ b/src/bunit/InternalsVisibleTo.cs @@ -1 +1,2 @@ [assembly: System.Runtime.CompilerServices.InternalsVisibleTo("Bunit.Tests, PublicKey=002400000480000094000000060200000024000052534131000400000100010001be6b1a2ca57b09b7040e2ab0993e515296ae22aef4031a4fe388a1336fe21f69c7e8610e9935de6ed18d94b5c98429f99ef62ce3d0af28a7088f856239368ea808ad4c448aa2a8075ed581f989f36ed0d0b8b1cfcaf1ff6a4506c8a99b7024b6eb56996d08e3c9c1cf5db59bff96fcc63ccad155ef7fc63aab6a69862437b6")] +[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("Bunit.Web.Query, PublicKey=002400000480000094000000060200000024000052534131000400000100010001be6b1a2ca57b09b7040e2ab0993e515296ae22aef4031a4fe388a1336fe21f69c7e8610e9935de6ed18d94b5c98429f99ef62ce3d0af28a7088f856239368ea808ad4c448aa2a8075ed581f989f36ed0d0b8b1cfcaf1ff6a4506c8a99b7024b6eb56996d08e3c9c1cf5db59bff96fcc63ccad155ef7fc63aab6a69862437b6")] diff --git a/tests/bunit.web.query.tests/Labels/LabelQueryExtensionsTest.cs b/tests/bunit.web.query.tests/Labels/LabelQueryExtensionsTest.cs index c58ae88b1..f59da3e7c 100644 --- a/tests/bunit.web.query.tests/Labels/LabelQueryExtensionsTest.cs +++ b/tests/bunit.web.query.tests/Labels/LabelQueryExtensionsTest.cs @@ -351,4 +351,146 @@ public void Test021(string htmlElementWithLabel) input.NodeName.ShouldBe(htmlElementWithLabel, StringCompareShould.IgnoreCase); input.Id.ShouldBe($"{htmlElementWithLabel}-with-label"); } + + [Fact(DisplayName = "FindAllByLabelText should return empty collection when no elements match")] + public void Test100() + { + var cut = Render(ps => + ps.AddChildContent("
No labels here
")); + + var elements = cut.FindAllByLabelText("Non-existent label"); + + elements.ShouldBeEmpty(); + } + + [Fact(DisplayName = "FindAllByLabelText should return multiple elements with same label text using for attribute")] + public void Test101() + { + var labelText = "Same Label"; + var cut = Render(ps => + ps.AddChildContent($""" + + + + + """)); + + var elements = cut.FindAllByLabelText(labelText); + + elements.Count.ShouldBe(2); + elements[0].Id.ShouldBe("input-1"); + elements[1].Id.ShouldBe("input-2"); + } + + [Fact(DisplayName = "FindAllByLabelText should return multiple elements with same aria-label")] + public void Test102() + { + var labelText = "Aria Label"; + var cut = Render(ps => + ps.AddChildContent($""" + + +