diff --git a/.github/workflows/blazorise-ci-basic.yml b/.github/workflows/blazorise-ci-basic.yml
index 46161100c5..b2b4b65f80 100644
--- a/.github/workflows/blazorise-ci-basic.yml
+++ b/.github/workflows/blazorise-ci-basic.yml
@@ -8,16 +8,16 @@ jobs:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v3
- name: Setup .NET 6
- uses: actions/setup-dotnet@v1
+ uses: actions/setup-dotnet@v3
with:
dotnet-version: '6.0.x'
include-prerelease: true
- name: Setup .NET 7
- uses: actions/setup-dotnet@v1
+ uses: actions/setup-dotnet@v3
with:
dotnet-version: '7.0.x'
include-prerelease: true
@@ -30,3 +30,9 @@ jobs:
- name: Run Unit Tests - Release
run: dotnet test ./Tests/Blazorise.Tests/Blazorise.Tests.csproj --configuration Release --no-restore --no-build --verbosity normal
+
+ - name: Prepare E2E Tests Dependencies
+ run: pwsh ./Tests/Blazorise.E2E.Tests/bin/Release/net7.0/playwright.ps1 install --with-deps
+
+ - name: Run E2E Tests - Release
+ run: dotnet test ./Tests/Blazorise.E2E.Tests/Blazorise.E2E.Tests.csproj --configuration Release --no-restore --no-build --verbosity normal
diff --git a/.runsettings b/.runsettings
new file mode 100644
index 0000000000..a93baeb974
--- /dev/null
+++ b/.runsettings
@@ -0,0 +1,23 @@
+
+
+
+
+ 4
+
+
+
+
+
+
+
+
+
+
+ chromium
+
+ true
+ --disable-gpu --no-sandbox
+ msedge
+
+
+
\ No newline at end of file
diff --git a/Blazorise.sln b/Blazorise.sln
index 7be4e02c5d..d108d5e299 100644
--- a/Blazorise.sln
+++ b/Blazorise.sln
@@ -38,6 +38,7 @@ EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{D1FF70C6-E002-47C3-B2D0-D0FFEF2BF37A}"
ProjectSection(SolutionItems) = preProject
.editorconfig = .editorconfig
+ .runsettings = .runsettings
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Blazorise.Charts.Streaming", "Source\Extensions\Blazorise.Charts.Streaming\Blazorise.Charts.Streaming.csproj", "{9AA305DA-A667-49E6-BDDA-7C976AD5BB3B}"
@@ -62,8 +63,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TodoApp", "Demos\Apps\TodoA
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Apps", "Apps", "{47240431-396C-4187-941A-9511D7B79D8D}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Blazorise.E2ETests", "Tests\Blazorise.E2ETests\Blazorise.E2ETests.csproj", "{A4218BB6-81C3-47A6-80F2-6FF6E227D142}"
-EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Blazorise.Tests", "Tests\Blazorise.Tests\Blazorise.Tests.csproj", "{8D91050E-1ACF-40C5-9DA4-5F94AB149A5E}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Blazorise.RichTextEdit", "Source\Extensions\Blazorise.RichTextEdit\Blazorise.RichTextEdit.csproj", "{EB4A0C35-C45D-4F0F-BF03-3ACFB53CB865}"
@@ -129,6 +128,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Blazorise.Tailwind", "Sourc
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Blazorise.Demo.Tailwind", "Demos\Blazorise.Demo.Tailwind\Blazorise.Demo.Tailwind.csproj", "{47EEB5B2-3CA1-436C-8317-E69F611FA1E3}"
EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Blazorise.E2E.Tests", "Tests\Blazorise.E2E.Tests\Blazorise.E2E.Tests.csproj", "{FA75DC9B-32F0-41DC-A51D-F851E79D62DB}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -223,10 +224,6 @@ Global
{FD072A38-6D23-49C1-93F9-4D7584A8A4A7}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FD072A38-6D23-49C1-93F9-4D7584A8A4A7}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FD072A38-6D23-49C1-93F9-4D7584A8A4A7}.Release|Any CPU.Build.0 = Release|Any CPU
- {A4218BB6-81C3-47A6-80F2-6FF6E227D142}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {A4218BB6-81C3-47A6-80F2-6FF6E227D142}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {A4218BB6-81C3-47A6-80F2-6FF6E227D142}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {A4218BB6-81C3-47A6-80F2-6FF6E227D142}.Release|Any CPU.Build.0 = Release|Any CPU
{8D91050E-1ACF-40C5-9DA4-5F94AB149A5E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8D91050E-1ACF-40C5-9DA4-5F94AB149A5E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8D91050E-1ACF-40C5-9DA4-5F94AB149A5E}.Release|Any CPU.ActiveCfg = Release|Any CPU
@@ -339,6 +336,10 @@ Global
{47EEB5B2-3CA1-436C-8317-E69F611FA1E3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{47EEB5B2-3CA1-436C-8317-E69F611FA1E3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{47EEB5B2-3CA1-436C-8317-E69F611FA1E3}.Release|Any CPU.Build.0 = Release|Any CPU
+ {FA75DC9B-32F0-41DC-A51D-F851E79D62DB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {FA75DC9B-32F0-41DC-A51D-F851E79D62DB}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {FA75DC9B-32F0-41DC-A51D-F851E79D62DB}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {FA75DC9B-32F0-41DC-A51D-F851E79D62DB}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -368,7 +369,6 @@ Global
{4DEB65E7-40BA-409E-9C26-6EF75ADF2601} = {C2D0A89F-530E-413F-9D0E-9EE2129A2275}
{FD072A38-6D23-49C1-93F9-4D7584A8A4A7} = {47240431-396C-4187-941A-9511D7B79D8D}
{47240431-396C-4187-941A-9511D7B79D8D} = {C2D0A89F-530E-413F-9D0E-9EE2129A2275}
- {A4218BB6-81C3-47A6-80F2-6FF6E227D142} = {D04C5874-4D6A-493E-8CF4-6C7922198563}
{8D91050E-1ACF-40C5-9DA4-5F94AB149A5E} = {D04C5874-4D6A-493E-8CF4-6C7922198563}
{EB4A0C35-C45D-4F0F-BF03-3ACFB53CB865} = {9731051E-0AA7-411E-A76A-987854F034DA}
{83B3D727-2C23-4A95-8478-85A854BA8325} = {9731051E-0AA7-411E-A76A-987854F034DA}
@@ -397,6 +397,7 @@ Global
{F9515890-3956-47A7-A8BB-B27333F4FC57} = {C2D0A89F-530E-413F-9D0E-9EE2129A2275}
{452E1C4E-F81A-46EC-AA86-7CC53FB1BCB3} = {73CD9574-5204-442D-A67C-CA7B038057C2}
{47EEB5B2-3CA1-436C-8317-E69F611FA1E3} = {C2D0A89F-530E-413F-9D0E-9EE2129A2275}
+ {FA75DC9B-32F0-41DC-A51D-F851E79D62DB} = {D04C5874-4D6A-493E-8CF4-6C7922198563}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {205B3EA4-470F-45DA-911E-346AF7D0A9A5}
diff --git a/Tests/BasicTestApp.Client/BasicTestApp.Client.csproj b/Tests/BasicTestApp.Client/BasicTestApp.Client.csproj
index f137a5cf66..b373e59ad7 100644
--- a/Tests/BasicTestApp.Client/BasicTestApp.Client.csproj
+++ b/Tests/BasicTestApp.Client/BasicTestApp.Client.csproj
@@ -2,8 +2,7 @@
net7.0
- Exe
- 10.0
+ true
diff --git a/Tests/BasicTestApp.Server/Program.cs b/Tests/BasicTestApp.Server/Program.cs
index 4949a601dd..60f945921d 100644
--- a/Tests/BasicTestApp.Server/Program.cs
+++ b/Tests/BasicTestApp.Server/Program.cs
@@ -1,22 +1,30 @@
-using Microsoft.AspNetCore;
-using Microsoft.AspNetCore.Hosting;
-using Microsoft.Extensions.Configuration;
+
+using Microsoft.AspNetCore.Builder;
+using Microsoft.Extensions.Logging;
namespace BasicTestApp.Server;
-
-public class Program
+public partial class Program
{
public static void Main( string[] args )
{
- BuildWebHost( args ).Run();
+ var builder = WebApplication.CreateBuilder( args );
+ builder.Logging.ClearProviders();
+
+ WebApplication app = builder.Build();
+
+ //app.UseWebAssemblyDebugging();
+ //app.UseHttpsRedirection();
+
+ app.UseBlazorFrameworkFiles();
+ app.UseStaticFiles();
+
+ app.UseRouting();
+
+ app.MapFallbackToFile( "index.html" );
+
+ app.Run();
}
+}
+
+public partial class Program { }
- public static IWebHost BuildWebHost( string[] args ) =>
- WebHost.CreateDefaultBuilder( args )
- .UseConfiguration( new ConfigurationBuilder()
- .AddCommandLine( args )
- .Build() )
- .UseStartup()
- .UseStaticWebAssets()
- .Build();
-}
\ No newline at end of file
diff --git a/Tests/BasicTestApp.Server/Startup.cs b/Tests/BasicTestApp.Server/Startup.cs
deleted file mode 100644
index 625a65f232..0000000000
--- a/Tests/BasicTestApp.Server/Startup.cs
+++ /dev/null
@@ -1,42 +0,0 @@
-#region Using directives
-using Microsoft.AspNetCore.Builder;
-using Microsoft.AspNetCore.Hosting;
-using Microsoft.Extensions.DependencyInjection;
-using Microsoft.Extensions.Hosting;
-#endregion
-
-namespace BasicTestApp.Server;
-
-public class Startup
-{
- // This method gets called by the runtime. Use this method to add services to the container.
- // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
- public void ConfigureServices( IServiceCollection services )
- {
- services
- .AddMvc()
- .AddNewtonsoftJson();
- }
-
- // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
- public void Configure( IApplicationBuilder app, IWebHostEnvironment env )
- {
-
- if ( env.IsDevelopment() )
- {
- app.UseDeveloperExceptionPage();
- app.UseWebAssemblyDebugging();
- }
-
- app.UseStaticFiles();
- app.UseBlazorFrameworkFiles();
-
- app.UseRouting();
-
- app.UseEndpoints( endpoints =>
- {
- endpoints.MapDefaultControllerRoute();
- endpoints.MapFallbackToFile( "index.html" );
- } );
- }
-}
\ No newline at end of file
diff --git a/Tests/Blazorise.E2E.Tests/Blazorise.E2E.Tests.csproj b/Tests/Blazorise.E2E.Tests/Blazorise.E2E.Tests.csproj
new file mode 100644
index 0000000000..4d13d85fef
--- /dev/null
+++ b/Tests/Blazorise.E2E.Tests/Blazorise.E2E.Tests.csproj
@@ -0,0 +1,27 @@
+
+
+
+ net7.0
+ enable
+
+ false
+ true
+ true
+
+
+
+
+
+
+
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+ all
+
+
+
+
+
+
+
+
+
diff --git a/Tests/Blazorise.E2E.Tests/DefaultExampleTests.cs b/Tests/Blazorise.E2E.Tests/DefaultExampleTests.cs
new file mode 100644
index 0000000000..e4d519496a
--- /dev/null
+++ b/Tests/Blazorise.E2E.Tests/DefaultExampleTests.cs
@@ -0,0 +1,46 @@
+namespace Blazorise.E2E.Tests;
+
+
+[Parallelizable( ParallelScope.Self )]
+[TestFixture]
+public class DefaultExampleTests : PageTest
+{
+ ///
+ /// This test serves as simple example of how to use Playwright. This was taken off playwright .NET docs.
+ ///
+ ///
+ //[Test]
+ public async Task HomepageHasPlaywrightInTitleAndGetStartedLinkLinkingtoTheIntroPage()
+ {
+ // Pause on the following line.
+ await Page.PauseAsync();
+
+ await Page.GotoAsync( "https://playwright.dev" );
+
+ // Expect a title "to contain" a substring.
+ await Expect( Page ).ToHaveTitleAsync( new Regex( "Playwright" ) );
+
+ // create a locator
+ var getStarted = Page.GetByRole( AriaRole.Link, new() { Name = "Get started" } );
+
+ // Expect an attribute "to be strictly equal" to the value.
+ await Expect( getStarted ).ToHaveAttributeAsync( "href", "/docs/intro" );
+
+ // Click the get started link.
+ await getStarted.ClickAsync();
+
+ // Expects the URL to contain intro.
+ await Expect( Page ).ToHaveURLAsync( new Regex( ".*intro" ) );
+ }
+}
+
+[Parallelizable( ParallelScope.Self )]
+[TestFixture]
+public class CopyMeTests : BlazorisePageTest
+{
+ [Test]
+ public async Task CopyMe()
+ {
+ await SelectTestComponent();
+ }
+}
\ No newline at end of file
diff --git a/Tests/Blazorise.E2E.Tests/Infrastructure/BlazorPageTest.cs b/Tests/Blazorise.E2E.Tests/Infrastructure/BlazorPageTest.cs
new file mode 100644
index 0000000000..87fbd49bb5
--- /dev/null
+++ b/Tests/Blazorise.E2E.Tests/Infrastructure/BlazorPageTest.cs
@@ -0,0 +1,61 @@
+using Microsoft.AspNetCore.Mvc.Testing;
+
+namespace Blazorise.E2E.Tests.Infrastructure;
+
+///
+/// Credit to : https://www.youtube.com/watch?v=lJa3YlUliEs
+///
+public class BlazorPageTest : PageTest
+{
+
+ protected static readonly Uri RootUri = new( "http://localhost:14695" );
+
+ private readonly WebApplicationFactory _webApplicationFactory = new() { };
+ private HttpClient _httpClient;
+
+ [SetUp]
+ public async Task Setup()
+ {
+ _httpClient = _webApplicationFactory.CreateClient( new()
+ {
+ BaseAddress = RootUri,
+ } );
+
+ await Context.RouteAsync( $"{RootUri.AbsoluteUri}**", async route =>
+ {
+ var request = route.Request;
+ var content = request.PostDataBuffer is { } postDataBuffer
+ ? new ByteArrayContent( postDataBuffer )
+ : null;
+
+ var requestMessage = new HttpRequestMessage( new( request.Method ), request.Url )
+ {
+ Content = content
+ };
+
+ foreach ( var header in request.Headers )
+ {
+ requestMessage.Headers.Add( header.Key, header.Value );
+ }
+
+ var response = await _httpClient.SendAsync( requestMessage );
+ var responseBody = await response.Content.ReadAsByteArrayAsync();
+ var responseHeaders = response.Content.Headers.Select( x => KeyValuePair.Create( x.Key, x.Value.FirstOrDefault() ?? string.Empty ) );
+
+ await route.FulfillAsync( new()
+ {
+ BodyBytes = responseBody,
+ Headers = responseHeaders,
+ Status = (int)response.StatusCode
+ } );
+
+ } );
+ }
+
+ [TearDown]
+ public void TearDown()
+ {
+ _httpClient?.Dispose();
+ }
+
+}
diff --git a/Tests/Blazorise.E2E.Tests/Infrastructure/BlazorisePageTest.cs b/Tests/Blazorise.E2E.Tests/Infrastructure/BlazorisePageTest.cs
new file mode 100644
index 0000000000..7dd4f6dadd
--- /dev/null
+++ b/Tests/Blazorise.E2E.Tests/Infrastructure/BlazorisePageTest.cs
@@ -0,0 +1,35 @@
+using Microsoft.AspNetCore.Components;
+
+namespace Blazorise.E2E.Tests.Infrastructure;
+
+
+public class BlazorisePageTest : BlazorPageTest
+{
+ ///
+ /// Override browser context options if needed.
+ ///
+ ///
+ public override BrowserNewContextOptions ContextOptions()
+ {
+ return new BrowserNewContextOptions()
+ {
+ Locale = "en-US"
+ };
+ }
+
+ ///
+ /// This is an helper specific to our test project, where we have a dropdown selection with the full name of the components.
+ /// This will also navigate to the root page.
+ ///
+ ///
+ ///
+ protected async Task SelectTestComponent() where TComponent : IComponent
+ {
+ await Page.GotoAsync( RootUri.AbsoluteUri );
+
+ var componentTypeName = typeof( TComponent ).FullName;
+ await Page.GetByRole( AriaRole.Combobox ).SelectOptionAsync( new[] { componentTypeName } );
+ }
+
+
+}
diff --git a/Tests/Blazorise.E2E.Tests/ReadMe.md b/Tests/Blazorise.E2E.Tests/ReadMe.md
new file mode 100644
index 0000000000..6d7f0ef3bb
--- /dev/null
+++ b/Tests/Blazorise.E2E.Tests/ReadMe.md
@@ -0,0 +1,91 @@
+# E2E tests with Playwright
+
+This test project uses Playwright with NUnit.
+
+The NUnit is chosen since there is already a helpful playwright helper package for NUnit, and parallelism is better supported.
+
+The API Docs are good; recommended pages for implementing tests:
+
+- https://playwright.dev/dotnet/docs/input
+- https://playwright.dev/dotnet/docs/test-assertions
+
+Below you will find instructions on how to use Playwright. This assumes you will be using the command line and that you will be positioned in the root of the E2E tests project.
+
+## Install
+
+1. Build the project, either by using the `dotnet build` command or `Ctrl+Shift+B` in Visual Studio.
+2. Execute the playwright powershell script to install necessary dependencies (browser dependencies, etc...), i.e:
+
+```bash
+powershell .\bin\Debug\net7.0\playwright.ps1 install --with-deps
+```
+
+> The script must be run in the folder `./Tests/Blazorise.E2E.Tests/`
+
+## Record / Implement new tests
+
+To start a record session to generate c# test code (a browser session & Playwright Inspector should be opened automatically):
+
+```bash
+powershell .\bin\Debug\net7.0\playwright.ps1 codegen http://localhost:14696
+```
+
+In the **Playwright Inspector**, please select **.NET C# NUnit** as the target library to generate the appropriate code.
+
+Please note that:
+
+- the testing demo is **BasicTestApp.Client** and you should run it in order to interact with the test application and generate tests.
+- you should make it so your new PageTest inherits from **BlazorisePageTest** as that setups the test application, and provides helpers.
+- in your test, you should navigate by using the provided **RootUri**, `await Page.GotoAsync( RootUri.AbsoluteUri );`
+ - In most tests you can just use the `SelectTestComponent` helper, which will automatically navigate to the strongly typed test page.
+
+
+## Debugging
+
+You can just debug the test as you normally would by using the debugger in Visual Studio.
+You can also disable headless mode so you can visually see the steps the test is taking on the test application.
+
+You can also use the Playwright Inspector to debug the test it will come up if you set `await Page.PauseAsync();` and are running in headed mode.
+
+https://playwright.dev/dotnet/docs/debug#headed-mode
+
+### Ways to disable headless mode
+
+To remove the headless mode, you can run any of the following:
+
+- `dotnet test -- Playwright.LaunchOptions.Headless=false`
+- `dotnet test --filter "MyTest" -- Playwright.LaunchOptions.Headless=false` (run a single test)
+- Set Headless to false in the .runsettings file that's located in the solution root folder
+- `set HEADED=1
+dotnet test`
+
+- `set PWDEBUG=1
+dotnet test`
+
+### Tracing will gather screenshots and other useful information about your test run.
+
+This will work even in headless mode.
+
+Insert at the beggining of the test:
+
+```cs
+// Start tracing before creating / navigating a page.
+await Context.Tracing.StartAsync( new()
+{
+ Screenshots = true,
+ Snapshots = true,
+ Sources = true
+} );
+```
+
+Insert at the end of the test: (You might want to wrap the test in a try/catch if the test is failing/throwing)
+
+```cs
+// Stop tracing and export it into a zip archive.
+await Context.Tracing.StopAsync( new()
+{
+ Path = "trace.zip"
+} );
+```
+
+You can then upload the zip file to https://trace.playwright.dev/ and see the screenshots and other relevant information.
\ No newline at end of file
diff --git a/Tests/Blazorise.E2E.Tests/Tests/Components/Button/ButtonTests.cs b/Tests/Blazorise.E2E.Tests/Tests/Components/Button/ButtonTests.cs
new file mode 100644
index 0000000000..61b069dd38
--- /dev/null
+++ b/Tests/Blazorise.E2E.Tests/Tests/Components/Button/ButtonTests.cs
@@ -0,0 +1,25 @@
+namespace Blazorise.E2E.Tests.Tests.Components.Button;
+
+[Parallelizable( ParallelScope.Self )]
+[TestFixture]
+public class ButtonTests : BlazorisePageTest
+{
+ [Test]
+ public async Task CanRaiseCallback()
+ {
+ await SelectTestComponent();
+
+ var buttonResult = Page.Locator( "#basic-button-event-result" );
+ await Page.GetByRole( AriaRole.Button, new() { Name = "Count" } ).ClickAsync();
+ await Expect( buttonResult ).ToHaveTextAsync( "1" );
+
+
+ await Page.GetByRole( AriaRole.Button, new() { Name = "Count" } ).ClickAsync();
+ await Expect( buttonResult ).ToHaveTextAsync( "2" );
+
+
+ await Page.GetByRole( AriaRole.Button, new() { Name = "Count" } ).ClickAsync();
+ await Expect( buttonResult ).ToHaveTextAsync( "3" );
+ }
+}
+
diff --git a/Tests/Blazorise.E2E.Tests/Tests/Components/Button/CloseButtonTests.cs b/Tests/Blazorise.E2E.Tests/Tests/Components/Button/CloseButtonTests.cs
new file mode 100644
index 0000000000..dd98d7abdc
--- /dev/null
+++ b/Tests/Blazorise.E2E.Tests/Tests/Components/Button/CloseButtonTests.cs
@@ -0,0 +1,33 @@
+namespace Blazorise.E2E.Tests.Tests.Components.Button;
+
+
+[Parallelizable( ParallelScope.Self )]
+[TestFixture]
+public class CloseButtonTests : BlazorisePageTest
+{
+ [Test]
+ public async Task CanRaiseCallback()
+ {
+ await SelectTestComponent();
+
+ var closeButtonResult = Page.Locator( "#close-button-event-result" );
+ await Page.GetByText( "× Count" ).ClickAsync();
+ await Expect( closeButtonResult ).ToHaveTextAsync( "1" );
+
+ await Page.GetByText( "× Count" ).ClickAsync();
+ await Expect( closeButtonResult ).ToHaveTextAsync( "2" );
+
+ await Page.GetByText( "× Count" ).ClickAsync();
+ await Expect( closeButtonResult ).ToHaveTextAsync( "3" );
+ }
+
+ [Test]
+ public async Task CanAutoClose()
+ {
+ await SelectTestComponent();
+
+ var autoCloseButtonResult = Page.Locator( "#autoclose-button-event-result" );
+ await Page.Locator( "#autoclose-button" ).ClickAsync();
+ await Expect( autoCloseButtonResult ).ToHaveTextAsync( "1" );
+ }
+}
diff --git a/Tests/Blazorise.E2E.Tests/Tests/Components/Dropdown/DropdownTests.cs b/Tests/Blazorise.E2E.Tests/Tests/Components/Dropdown/DropdownTests.cs
new file mode 100644
index 0000000000..5a7d56269c
--- /dev/null
+++ b/Tests/Blazorise.E2E.Tests/Tests/Components/Dropdown/DropdownTests.cs
@@ -0,0 +1,25 @@
+namespace Blazorise.E2E.Tests.Tests.Components.Dropdown;
+
+[Parallelizable( ParallelScope.Self )]
+[TestFixture]
+public class DropdownTests : BlazorisePageTest
+{
+ [Test]
+ public async Task CanShowAndHideDropdownComponent()
+ {
+ await SelectTestComponent();
+
+ var button = Page.GetByRole( AriaRole.Button );
+ var dropdown = Page.Locator( ".dropdown" );
+ var dropdownMenu = Page.Locator( ".dropdown-menu" );
+
+ await button.ClickAsync();
+ await Expect( dropdown ).ToHaveClassAsync( "dropdown show" );
+ await Expect( dropdownMenu ).ToHaveClassAsync( "dropdown-menu show" );
+
+ await button.ClickAsync();
+ await Expect( dropdown ).Not.ToHaveClassAsync( "dropdown show" );
+ await Expect( dropdownMenu ).Not.ToHaveClassAsync( "dropdown-menu show" );
+
+ }
+}
diff --git a/Tests/Blazorise.E2E.Tests/Tests/Components/NumericEdit/NumericEditTests.cs b/Tests/Blazorise.E2E.Tests/Tests/Components/NumericEdit/NumericEditTests.cs
new file mode 100644
index 0000000000..e643fb72d6
--- /dev/null
+++ b/Tests/Blazorise.E2E.Tests/Tests/Components/NumericEdit/NumericEditTests.cs
@@ -0,0 +1,181 @@
+namespace Blazorise.E2E.Tests.Tests.Components.NumericEdit;
+
+[Parallelizable( ParallelScope.Self )]
+[TestFixture]
+public class NumericEditTests : BlazorisePageTest
+{
+ [Test]
+ public async Task CanChangeUndefinedIntegerUsingEvent()
+ {
+ await SelectTestComponent();
+
+ var sut = Page.Locator( "#int-event-initially-undefined" );
+ var input = sut.Locator( "input[type=number]" );
+ var result = sut.Locator( "#int-event-initially-undefined-result" );
+
+ await Expect( result ).ToHaveTextAsync( "0" );
+
+ await input.FillAsync( "100" );
+ await Expect( result ).ToHaveTextAsync( "100" );
+
+ await Page.Keyboard.PressAsync( "Backspace" );
+ await Expect( result ).ToHaveTextAsync( "10" );
+ }
+
+ [Test]
+ public async Task CanChangeNullableIntegerUsingEvent()
+ {
+ await SelectTestComponent();
+
+ var sut = Page.Locator( "#nullable-int-event-initially-null" );
+ var input = sut.Locator( "input[type=number]" );
+ var result = sut.Locator( "#nullable-int-event-initially-null-result" );
+
+ await Expect( result ).ToHaveTextAsync( string.Empty );
+
+ await input.FillAsync( "100" );
+ await Expect( result ).ToHaveTextAsync( "100" );
+
+ await Page.Keyboard.PressAsync( "Backspace" );
+ await Expect( result ).ToHaveTextAsync( "10" );
+ }
+
+ [Test]
+ public async Task CanChangeUndefinedDecimalUsingEvent()
+ {
+ await SelectTestComponent();
+
+ var sut = Page.Locator( "#decimal-event-initially-undefined" );
+ var input = sut.Locator( "input[type=number]" );
+ var result = sut.Locator( "#decimal-event-initially-undefined-result" );
+
+ await Expect( result ).ToHaveTextAsync( "0" );
+
+ await input.FillAsync( "100" );
+ await Expect( result ).ToHaveTextAsync( "100" );
+
+ await Page.Keyboard.PressAsync( "Backspace" );
+ await Expect( result ).ToHaveTextAsync( "10" );
+ }
+
+ [Test]
+ public async Task CanChangeNullableDecimalUsingEvent()
+ {
+ await SelectTestComponent();
+
+ var sut = Page.Locator( "#nullable-decimal-event-initially-null" );
+ var input = sut.Locator( "input[type=number]" );
+ var result = sut.Locator( "#nullable-decimal-event-initially-null-result" );
+
+ await Expect( result ).ToHaveTextAsync( string.Empty );
+
+ await input.FillAsync( "100" );
+ await Expect( result ).ToHaveTextAsync( "100" );
+
+ await Page.Keyboard.PressAsync( "Backspace" );
+ await Expect( result ).ToHaveTextAsync( "10" );
+ }
+
+ [Test]
+ public async Task CanChangeValueWithStepDefault()
+ {
+ await SelectTestComponent();
+
+ var sut = Page.Locator( "#step-change-default" );
+ var input = sut.Locator( "input[type=number]" );
+ var result = sut.Locator( "#step-change-default-result" );
+
+ await Expect( result ).ToHaveTextAsync( "1" );
+
+ await input.FocusAsync();
+ await Page.Keyboard.PressAsync( "ArrowUp" );
+ await Page.Keyboard.PressAsync( "ArrowUp" );
+ await Expect( result ).ToHaveTextAsync( "3" );
+
+ await Page.Keyboard.PressAsync( "ArrowDown" );
+ await Expect( result ).ToHaveTextAsync( "2" );
+ }
+
+ [Test]
+ public async Task CanChangeValueWithStepBy2()
+ {
+ await SelectTestComponent();
+
+ var sut = Page.Locator( "#step-change-by-2" );
+ var input = sut.Locator( "input[type=number]" );
+ var result = sut.Locator( "#step-change-by-2-result" );
+
+ await Expect( result ).ToHaveTextAsync( "2" );
+
+ await input.FocusAsync();
+ await Page.Keyboard.PressAsync( "ArrowUp" );
+ await Page.Keyboard.PressAsync( "ArrowUp" );
+ await Expect( result ).ToHaveTextAsync( "6" );
+
+ await Page.Keyboard.PressAsync( "ArrowDown" );
+ await Expect( result ).ToHaveTextAsync( "4" );
+ }
+
+ // [Test]
+ // Removed temporarly as execution fails on a colleague's machine for some unknown reason...
+ // Have to figure out if it's something with playwright configuration... or something else...
+ public async Task CanTypeNumberWithDotDecimalSeparator()
+ {
+ await SelectTestComponent();
+
+ var sut = Page.Locator( "#decimal-separator-with-dot" );
+ var input = sut.Locator( "input[type=number]" );
+ var result = sut.Locator( "#decimal-separator-with-dot-result" );
+
+ await Expect( result ).ToHaveTextAsync( "42.5" );
+
+ await input.FocusAsync();
+ await Page.Keyboard.PressAsync( "6" );
+ await Expect( result ).ToHaveTextAsync( "42.56" );
+
+ await Page.Keyboard.PressAsync( "Backspace" );
+ await Page.Keyboard.PressAsync( "Backspace" );
+
+ await Expect( result ).ToHaveTextAsync( "42" );
+
+ await Page.Keyboard.PressAsync( ".", new KeyboardPressOptions() { Delay = 100 } );
+ await Page.Keyboard.PressAsync( "3" );
+ await Expect( result ).ToHaveTextAsync( "42.3" );
+ }
+
+ [Test]
+ public async Task CanTypeMinMax()
+ {
+ await SelectTestComponent();
+
+ var sut = Page.Locator( "#decimal-min-max-non-nullable" );
+ var input = sut.Locator( "input[type=number]" );
+ var result = sut.Locator( "#decimal-min-max-non-nullable-result" );
+
+ await Expect( result ).ToHaveTextAsync( "0" );
+
+ await input.FillAsync( "2" );
+ await Expect( result ).ToHaveTextAsync( "2" );
+
+ await input.BlurAsync();
+ await Expect( result ).ToHaveTextAsync( "10" );
+
+ await input.BlurAsync();
+ await input.FillAsync( "15" );
+ await Expect( result ).ToHaveTextAsync( "15" );
+ await input.BlurAsync();
+ await Expect( result ).ToHaveTextAsync( expected: "15" );
+
+ await input.BlurAsync();
+ await input.FillAsync( "21" );
+ await Expect( result ).ToHaveTextAsync( "21" );
+ await input.BlurAsync();
+ await Expect( result ).ToHaveTextAsync( expected: "20" );
+
+ await input.BlurAsync();
+ await input.FillAsync( "0" );
+ await Expect( result ).ToHaveTextAsync( "0" );
+ await input.BlurAsync();
+ await Expect( result ).ToHaveTextAsync( expected: "10" );
+ }
+}
diff --git a/Tests/Blazorise.E2E.Tests/Tests/Components/NumericEdit/ValidateNumericEditTests.cs b/Tests/Blazorise.E2E.Tests/Tests/Components/NumericEdit/ValidateNumericEditTests.cs
new file mode 100644
index 0000000000..e195ec261f
--- /dev/null
+++ b/Tests/Blazorise.E2E.Tests/Tests/Components/NumericEdit/ValidateNumericEditTests.cs
@@ -0,0 +1,104 @@
+namespace Blazorise.E2E.Tests.Tests.Components.NumericEdit;
+
+
+[Parallelizable( ParallelScope.Self )]
+[TestFixture]
+public class ValidateNumericEditTests : BlazorisePageTest
+{
+ [Test]
+ public async Task CanValidateNumeric_InitiallyBlank()
+ {
+ await SelectTestComponent();
+
+ var sut = Page.Locator( "#validate-numeric-initially-blank" );
+ var textBox = sut.Locator( "input[type=number]" );
+ var validationFeedback = sut.GetByText( "error" );
+
+ await ExpectTo_StartInvalid_ValidUponFill_InvalidUponClear( textBox, validationFeedback );
+ }
+
+ [Test]
+ public async Task CanValidateNumeric_InitiallyPopulated()
+ {
+ await SelectTestComponent();
+
+ var sut = Page.Locator( "#validate-numeric-initially-populated" );
+ var textBox = sut.Locator( "input[type=number]" );
+ var validationFeedback = sut.GetByText( "error" );
+
+ await ExpectTo_StartValid_InvalidUponClear_ValidUponFill( textBox, validationFeedback );
+ }
+
+ [Test]
+ public async Task CanValidateNumericWithBind_InitiallyBlank()
+ {
+ await SelectTestComponent();
+
+ var sut = Page.Locator( "#validate-numeric-with-bind-initially-blank" );
+ var textBox = sut.Locator( "input[type=number]" );
+ var validationFeedback = sut.GetByText( "error" );
+
+ await ExpectTo_StartInvalid_ValidUponFill_InvalidUponClear( textBox, validationFeedback );
+ }
+
+ [Test]
+ public async Task CanValidateNumericWithBind_InitiallyPopulated()
+ {
+
+ await SelectTestComponent();
+
+ var sut = Page.Locator( "#validate-numeric-with-bind-initially-populated" );
+ var textBox = sut.Locator( "input[type=number]" );
+ var validationFeedback = sut.GetByText( "error" );
+
+ await ExpectTo_StartValid_InvalidUponClear_ValidUponFill( textBox, validationFeedback );
+ }
+
+ [Test]
+ public async Task CanValidateNumericWithEvent_InitiallyBlank()
+ {
+
+ await SelectTestComponent();
+
+ var sut = Page.Locator( "#validate-numeric-with-event-initially-blank" );
+ var textBox = sut.Locator( "input[type=number]" );
+ var validationFeedback = sut.GetByText( "error" );
+
+ await ExpectTo_StartInvalid_ValidUponFill_InvalidUponClear( textBox, validationFeedback );
+ }
+
+ [Test]
+ public async Task CanValidateNumericWithEvent_InitiallyPopulated()
+ {
+ await SelectTestComponent();
+
+ var sut = Page.Locator( "#validate-numeric-with-event-initially-populated" );
+ var textBox = sut.Locator( "input[type=number]" );
+ var validationFeedback = sut.GetByText( "error" );
+
+ await ExpectTo_StartValid_InvalidUponClear_ValidUponFill( textBox, validationFeedback );
+ }
+
+ private async Task ExpectTo_StartInvalid_ValidUponFill_InvalidUponClear( ILocator textBox, ILocator validationFeedback )
+ {
+ await Expect( validationFeedback ).ToHaveClassAsync( "invalid-feedback" );
+
+ await textBox.FillAsync( "1" );
+ await Expect( validationFeedback ).ToBeHiddenAsync();
+
+ await textBox.FillAsync( "" );
+ await Expect( validationFeedback ).ToHaveClassAsync( "invalid-feedback" );
+ }
+
+ private async Task ExpectTo_StartValid_InvalidUponClear_ValidUponFill( ILocator textBox, ILocator validationFeedback )
+ {
+ await Expect( validationFeedback ).ToBeHiddenAsync();
+
+ await textBox.FillAsync( "" );
+ await Expect( validationFeedback ).ToHaveClassAsync( "invalid-feedback" );
+
+ await textBox.FillAsync( "1" );
+ await Expect( validationFeedback ).ToBeHiddenAsync();
+ }
+
+}
diff --git a/Tests/Blazorise.E2E.Tests/Tests/Components/RadioGroup/RadioGroupTests.cs b/Tests/Blazorise.E2E.Tests/Tests/Components/RadioGroup/RadioGroupTests.cs
new file mode 100644
index 0000000000..a4f412277e
--- /dev/null
+++ b/Tests/Blazorise.E2E.Tests/Tests/Components/RadioGroup/RadioGroupTests.cs
@@ -0,0 +1,36 @@
+namespace Blazorise.E2E.Tests.Tests.Components.RadioGroup;
+
+[Parallelizable( ParallelScope.Self )]
+[TestFixture]
+public class RadioGroupTests : BlazorisePageTest
+{
+ [Test]
+ public async Task CanCheckString_InitiallyChecked()
+ {
+ await SelectTestComponent();
+
+ var sut = Page.Locator( "#radiogroup-event-initially-selected" );
+ var radioRed = sut.Locator( ".radioR" );
+ var radioGreen = sut.Locator( ".radioG" );
+ var radioBlue = sut.Locator( ".radioB" );
+ var result = sut.Locator( "#radiogroup-event-initially-selected-result" );
+
+ await Expect( radioGreen ).ToBeCheckedAsync();
+ await Expect( radioRed ).Not.ToBeCheckedAsync();
+ await Expect( radioBlue ).Not.ToBeCheckedAsync();
+ await Expect( result ).ToHaveTextAsync( "green" );
+
+ await radioRed.ClickAsync();
+ await Expect( radioRed ).ToBeCheckedAsync();
+ await Expect( radioGreen ).Not.ToBeCheckedAsync();
+ await Expect( radioBlue ).Not.ToBeCheckedAsync();
+ await Expect( result ).ToHaveTextAsync( "red" );
+
+
+ await radioBlue.ClickAsync();
+ await Expect( radioBlue ).ToBeCheckedAsync();
+ await Expect( radioRed ).Not.ToBeCheckedAsync();
+ await Expect( radioGreen ).Not.ToBeCheckedAsync();
+ await Expect( result ).ToHaveTextAsync( "blue" );
+ }
+}
\ No newline at end of file
diff --git a/Tests/Blazorise.E2E.Tests/Tests/Components/Select/SelectTests.cs b/Tests/Blazorise.E2E.Tests/Tests/Components/Select/SelectTests.cs
new file mode 100644
index 0000000000..f0f6b05551
--- /dev/null
+++ b/Tests/Blazorise.E2E.Tests/Tests/Components/Select/SelectTests.cs
@@ -0,0 +1,45 @@
+namespace Blazorise.E2E.Tests.Tests.Components.Select;
+
+[Parallelizable( ParallelScope.Self )]
+[TestFixture]
+public class SelectTests : BlazorisePageTest
+{
+ [Test]
+ public async Task SelectOptions()
+ {
+ await SelectTestComponent();
+
+
+ var sut = Page.Locator( "#select-value-initialy-selected" );
+ var select = sut.GetByRole( AriaRole.Combobox );
+ var btnOne = sut.Locator( ".btn-primary" );
+ var btnTwo = sut.Locator( ".btn-secondary" );
+ var result = sut.Locator( "#select-value-initialy-selected-result" );
+
+ await Expect( select ).ToHaveValueAsync( "two" );
+ await Expect( result ).ToHaveTextAsync( "two" );
+
+ await SelectAndExpectValue( select, result, "one" );
+ await SelectAndExpectValue( select, result, "two" );
+ await SelectAndExpectValue( select, result, "three" );
+
+ await btnOne.ClickAsync();
+ await Expect( select ).ToHaveValueAsync( "one" );
+ await Expect( result ).ToHaveTextAsync( "one" );
+
+ await btnTwo.ClickAsync();
+ await Expect( select ).ToHaveValueAsync( "two" );
+ await Expect( result ).ToHaveTextAsync( "two" );
+
+ await btnOne.ClickAsync();
+ await Expect( select ).ToHaveValueAsync( "one" );
+ await Expect( result ).ToHaveTextAsync( "one" );
+ }
+
+ private async Task SelectAndExpectValue( ILocator select, ILocator result, string value )
+ {
+ await select.SelectOptionAsync( value );
+ await Expect( result ).ToHaveTextAsync( value );
+ await Expect( select ).ToHaveValueAsync( value );
+ }
+}
\ No newline at end of file
diff --git a/Tests/Blazorise.E2E.Tests/Tests/Components/Select/ValidateSelectTests.cs b/Tests/Blazorise.E2E.Tests/Tests/Components/Select/ValidateSelectTests.cs
new file mode 100644
index 0000000000..f55f25fcd0
--- /dev/null
+++ b/Tests/Blazorise.E2E.Tests/Tests/Components/Select/ValidateSelectTests.cs
@@ -0,0 +1,190 @@
+namespace Blazorise.E2E.Tests.Tests.Components.Select;
+
+
+[Parallelizable( ParallelScope.Self )]
+[TestFixture]
+public class ValidateSelectTests : BlazorisePageTest
+{
+ [Test]
+ public async Task CanValidateString_InitiallyBlank()
+ {
+ await SelectTestComponent();
+
+ var sut = Page.Locator( "#validate-string-initially-blank" );
+ var select = sut.GetByRole( AriaRole.Combobox );
+ var validationFeedback = sut.GetByText( "error" );
+
+ await ExpectTo_StartInvalid_ValidUponFill_InvalidUponClear( select, validationFeedback );
+ }
+
+ [Test]
+ public async Task CanValidateStringWithBind_InitiallyBlank()
+ {
+ await SelectTestComponent();
+
+ var sut = Page.Locator( "#validate-string-with-bind-initially-blank" );
+ var select = sut.GetByRole( AriaRole.Combobox );
+ var validationFeedback = sut.GetByText( "error" );
+
+ await ExpectTo_StartInvalid_ValidUponFill_InvalidUponClear( select, validationFeedback );
+ }
+
+ [Test]
+ public async Task CanValidateStringWithBind_InitiallySelected()
+ {
+ await SelectTestComponent();
+
+ var sut = Page.Locator( "#validate-string-with-bind-initially-selected" );
+ var select = sut.GetByRole( AriaRole.Combobox );
+ var validationFeedback = sut.GetByText( "error" );
+
+ await ExpectTo_StartValid_InvalidUponClear_ValidUponFill( select, validationFeedback );
+ }
+
+ [Test]
+ public async Task CanValidateStringWithEvent_InitiallyBlank()
+ {
+
+ await SelectTestComponent();
+
+ var sut = Page.Locator( "#validate-string-with-event-initially-blank" );
+ var select = sut.GetByRole( AriaRole.Combobox );
+ var validationFeedback = sut.GetByText( "error" );
+
+ await ExpectTo_StartInvalid_ValidUponFill_InvalidUponClear( select, validationFeedback );
+ }
+
+ [Test]
+ public async Task CanValidateStringWithEvent_InitiallySelected()
+ {
+
+ await SelectTestComponent();
+
+ var sut = Page.Locator( "#validate-string-with-event-initially-selected" );
+ var select = sut.GetByRole( AriaRole.Combobox );
+ var validationFeedback = sut.GetByText( "error" );
+
+ await ExpectTo_StartValid_InvalidUponClear_ValidUponFill( select, validationFeedback );
+ }
+
+ [Test]
+ public async Task CanValidateInt_InitiallyBlank()
+ {
+ await SelectTestComponent();
+
+ var sut = Page.Locator( "#validate-int-initially-blank" );
+ var select = sut.GetByRole( AriaRole.Combobox );
+ var validationFeedback = sut.GetByText( "error" );
+
+ await ExpectTo_StartInvalid_ValidUponFill_InvalidUponClear( select, validationFeedback );
+ }
+
+ [Test]
+ public async Task CanValidateIntWithBind_InitiallyBlank()
+ {
+ await SelectTestComponent();
+
+ var sut = Page.Locator( "#validate-int-with-bind-initially-blank" );
+ var select = sut.GetByRole( AriaRole.Combobox );
+ var validationFeedback = sut.GetByText( "error" );
+
+ await ExpectTo_StartInvalid_ValidUponFill_InvalidUponClear( select, validationFeedback );
+ }
+
+ [Test]
+ public async Task CanValidateIntWithBind_InitiallySelected()
+ {
+ await SelectTestComponent();
+
+ var sut = Page.Locator( "#validate-int-with-bind-initially-selected" );
+ var select = sut.GetByRole( AriaRole.Combobox );
+ var validationFeedback = sut.GetByText( "error" );
+
+ await ExpectTo_StartValid_InvalidUponClear_ValidUponFill( select, validationFeedback );
+ }
+
+ [Test]
+ public async Task CanValidateEnum_InitiallyBlank()
+ {
+ await SelectTestComponent();
+
+ var sut = Page.Locator( "#validate-enum-initially-blank" );
+ var select = sut.GetByRole( AriaRole.Combobox );
+ var validationFeedback = sut.GetByText( "error" );
+
+ await ExpectTo_StartInvalid_ValidUponFill_InvalidUponClear( select, validationFeedback );
+ }
+
+ [Test]
+ public async Task CanValidateEnumWithBind_InitiallyBlank()
+ {
+ await SelectTestComponent();
+
+ var sut = Page.Locator( "#validate-enum-with-bind-initially-blank" );
+ var select = sut.GetByRole( AriaRole.Combobox );
+ var validationFeedback = sut.GetByText( "error" );
+
+ await ExpectTo_StartInvalid_ValidUponFill_InvalidUponClear( select, validationFeedback );
+ }
+
+ [Test]
+ public async Task CanValidateEnumWithBind_InitiallySelected()
+ {
+ await SelectTestComponent();
+
+ var sut = Page.Locator( "#validate-enum-with-bind-initially-selected" );
+ var select = sut.GetByRole( AriaRole.Combobox );
+ var validationFeedback = sut.GetByText( "error" );
+
+ await ExpectTo_StartValid_InvalidUponClear_ValidUponFill( select, validationFeedback );
+ }
+
+ [Test]
+ public async Task CanValidateMultiString_InitiallyBlank()
+ {
+ await SelectTestComponent();
+
+ var sut = Page.Locator( "#validate-multi-string-initially-blank" );
+ var select = sut.GetByRole( AriaRole.Listbox );
+ var validationFeedback = sut.GetByText( "error" );
+
+ var options = await select.Locator( "option" ).AllAsync();
+
+
+ await Expect( validationFeedback ).ToHaveClassAsync( "invalid-feedback" );
+ await select.SelectOptionAsync( new SelectOptionValue[] { new() { Index = 1 }, new() { Index = 2 } } );
+ await Expect( validationFeedback ).ToBeHiddenAsync();
+
+ await options[1].ClickAsync( new() { Modifiers = new KeyboardModifier[] { KeyboardModifier.Control } } );
+ await Expect( validationFeedback ).ToBeHiddenAsync();
+
+ await options[2].ClickAsync( new() { Modifiers = new KeyboardModifier[] { KeyboardModifier.Control } } );
+ await Expect( validationFeedback ).ToHaveClassAsync( "invalid-feedback" );
+
+ await select.SelectOptionAsync( new SelectOptionValue() { Index = 0 } );
+ await Expect( validationFeedback ).ToBeHiddenAsync();
+ }
+
+ private async Task ExpectTo_StartInvalid_ValidUponFill_InvalidUponClear( ILocator select, ILocator validationFeedback )
+ {
+ await Expect( validationFeedback ).ToHaveClassAsync( "invalid-feedback" );
+
+ await select.SelectOptionAsync( new SelectOptionValue() { Index = 1 } );
+ await Expect( validationFeedback ).ToBeHiddenAsync();
+
+ await select.SelectOptionAsync( new SelectOptionValue() { Index = 0 } );
+ await Expect( validationFeedback ).ToHaveClassAsync( "invalid-feedback" );
+ }
+
+ private async Task ExpectTo_StartValid_InvalidUponClear_ValidUponFill( ILocator select, ILocator validationFeedback )
+ {
+ await Expect( validationFeedback ).ToBeHiddenAsync();
+
+ await select.SelectOptionAsync( new SelectOptionValue() { Index = 0 } );
+ await Expect( validationFeedback ).ToHaveClassAsync( "invalid-feedback" );
+
+ await select.SelectOptionAsync( new SelectOptionValue() { Index = 1 } );
+ await Expect( validationFeedback ).ToBeHiddenAsync();
+ }
+
+}
diff --git a/Tests/Blazorise.E2E.Tests/Tests/Components/Tabs/TabsTests.cs b/Tests/Blazorise.E2E.Tests/Tests/Components/Tabs/TabsTests.cs
new file mode 100644
index 0000000000..0f043c7658
--- /dev/null
+++ b/Tests/Blazorise.E2E.Tests/Tests/Components/Tabs/TabsTests.cs
@@ -0,0 +1,63 @@
+namespace Blazorise.E2E.Tests.Tests.Components.Tabs;
+
+[Parallelizable( ParallelScope.Self )]
+[TestFixture]
+public class TabsTests : BlazorisePageTest
+{
+ [Test]
+ public async Task CanSelectTabs()
+ {
+ await SelectTestComponent();
+
+
+ var sut = Page.Locator( "#basic-tabs" );
+ var links = await sut.Locator( "a" ).AllAsync();
+
+ var tabContent = sut.Locator( ".tab-content" );
+ var panels = await tabContent.Locator( "div" ).AllAsync();
+
+ Assert.IsNotEmpty( links );
+ Assert.IsNotEmpty( panels );
+
+ await DoNotExpectShowClass( links[0] );
+ await ExpectShowClass( links[1] );
+ await DoNotExpectShowClass( links[2] );
+
+
+ await DoNotExpectShowClass( panels[0] );
+ await ExpectShowClass( panels[1] );
+ await DoNotExpectShowClass( panels[2] );
+
+ await links[0].ClickAsync();
+ await ExpectShowClass( links[0] );
+ await DoNotExpectShowClass( links[1] );
+ await DoNotExpectShowClass( links[2] );
+
+
+ await ExpectShowClass( panels[0] );
+ await DoNotExpectShowClass( panels[1] );
+ await DoNotExpectShowClass( panels[2] );
+
+ await links[2].ClickAsync();
+ await DoNotExpectShowClass( links[0] );
+ await DoNotExpectShowClass( links[1] );
+ await ExpectShowClass( links[2] );
+
+
+ await DoNotExpectShowClass( panels[0] );
+ await DoNotExpectShowClass( panels[1] );
+ await ExpectShowClass( panels[2] );
+
+ }
+
+ private async Task ExpectShowClass( ILocator locator )
+ {
+ await Expect( locator ).ToHaveClassAsync( expected: new Regex( "show" ) );
+ }
+
+ private async Task DoNotExpectShowClass( ILocator locator )
+ {
+ await Expect( locator ).Not.ToHaveClassAsync( expected: new Regex( "show" ) );
+ }
+
+}
\ No newline at end of file
diff --git a/Tests/Blazorise.E2E.Tests/Tests/Components/TextEdit/AsyncValidateTextEditTests.cs b/Tests/Blazorise.E2E.Tests/Tests/Components/TextEdit/AsyncValidateTextEditTests.cs
new file mode 100644
index 0000000000..f79be84a1f
--- /dev/null
+++ b/Tests/Blazorise.E2E.Tests/Tests/Components/TextEdit/AsyncValidateTextEditTests.cs
@@ -0,0 +1,107 @@
+namespace Blazorise.E2E.Tests.Tests.Components.TextEdit;
+
+
+[Parallelizable( ParallelScope.Self )]
+[TestFixture]
+public class AsyncValidateTextEditTests : BlazorisePageTest
+{
+ [Test]
+ public async Task CanValidateText_InitiallyBlank()
+ {
+ await SelectTestComponent();
+
+ var sut = Page.Locator( "#validate-text-initially-blank" );
+ var textBox = sut.GetByRole( AriaRole.Textbox );
+ var validationFeedback = sut.GetByText( "error" );
+
+ await ExpectTo_StartInvalid_ValidUponFill_InvalidUponClear( textBox, validationFeedback );
+ }
+
+
+
+ [Test]
+ public async Task CanValidateText_InitiallyPopulated()
+ {
+ await SelectTestComponent();
+
+ var sut = Page.Locator( "#validate-text-initially-populated" );
+ var textBox = sut.GetByRole( AriaRole.Textbox );
+ var validationFeedback = sut.GetByText( "error" );
+
+ await ExpectTo_StartValid_InvalidUponClear_ValidUponFill( textBox, validationFeedback );
+ }
+
+
+
+ [Test]
+ public async Task CanValidateTextWithBind_InitiallyBlank()
+ {
+ await SelectTestComponent();
+
+ var sut = Page.Locator( "#validate-text-with-bind-initially-blank" );
+ var textBox = sut.GetByRole( AriaRole.Textbox );
+ var validationFeedback = sut.GetByText( "error" );
+
+ await ExpectTo_StartInvalid_ValidUponFill_InvalidUponClear( textBox, validationFeedback );
+ }
+
+ [Test]
+ public async Task CanValidateTextWithBind_InitiallyPopulated()
+ {
+
+ await SelectTestComponent();
+
+ var sut = Page.Locator( "#validate-text-with-bind-initially-populated" );
+ var textBox = sut.GetByRole( AriaRole.Textbox );
+ var validationFeedback = sut.GetByText( "error" );
+
+ await ExpectTo_StartValid_InvalidUponClear_ValidUponFill( textBox, validationFeedback );
+ }
+
+ [Test]
+ public async Task CanValidateTextWithEvent_InitiallyBlank()
+ {
+ await SelectTestComponent();
+
+ var sut = Page.Locator( "#validate-text-with-event-initially-blank" );
+ var textBox = sut.GetByRole( AriaRole.Textbox );
+ var validationFeedback = sut.GetByText( "error" );
+
+ await ExpectTo_StartInvalid_ValidUponFill_InvalidUponClear( textBox, validationFeedback );
+ }
+
+ [Test]
+ public async Task CanValidateTextWithEvent_InitiallyPopulated()
+ {
+ await SelectTestComponent();
+
+ var sut = Page.Locator( "#validate-text-with-event-initially-populated" );
+ var textBox = sut.GetByRole( AriaRole.Textbox );
+ var validationFeedback = sut.GetByText( "error" );
+
+ await ExpectTo_StartValid_InvalidUponClear_ValidUponFill( textBox, validationFeedback );
+ }
+
+ private async Task ExpectTo_StartInvalid_ValidUponFill_InvalidUponClear( ILocator textBox, ILocator validationFeedback )
+ {
+ await Expect( validationFeedback ).ToHaveClassAsync( "invalid-feedback" );
+
+ await textBox.FillAsync( "some text" );
+ await Expect( validationFeedback ).ToBeHiddenAsync();
+
+ await textBox.FillAsync( "" );
+ await Expect( validationFeedback ).ToHaveClassAsync( "invalid-feedback" );
+ }
+
+ private async Task ExpectTo_StartValid_InvalidUponClear_ValidUponFill( ILocator textBox, ILocator validationFeedback )
+ {
+ await Expect( validationFeedback ).ToBeHiddenAsync();
+
+ await textBox.FillAsync( "" );
+ await Expect( validationFeedback ).ToHaveClassAsync( "invalid-feedback" );
+
+ await textBox.FillAsync( "some text" );
+ await Expect( validationFeedback ).ToBeHiddenAsync();
+ }
+
+}
diff --git a/Tests/Blazorise.E2E.Tests/Tests/Components/TextEdit/TextEditTests.cs b/Tests/Blazorise.E2E.Tests/Tests/Components/TextEdit/TextEditTests.cs
new file mode 100644
index 0000000000..5ab625978f
--- /dev/null
+++ b/Tests/Blazorise.E2E.Tests/Tests/Components/TextEdit/TextEditTests.cs
@@ -0,0 +1,58 @@
+namespace Blazorise.E2E.Tests.Tests.Components.TextEdit;
+
+
+[Parallelizable( ParallelScope.Self )]
+[TestFixture]
+public class TextEditTests : BlazorisePageTest
+{
+ [Test]
+ public async Task CanChangeText()
+ {
+ await SelectTestComponent();
+
+ var sut = Page.Locator( "#text-basic" );
+ var textBox = sut.GetByRole( AriaRole.Textbox );
+
+ await Expect( textBox ).ToHaveValueAsync( string.Empty );
+
+ await textBox.FillAsync( "abc" );
+ await Expect( textBox ).ToHaveValueAsync( "abc" );
+ }
+
+ [Test]
+ public async Task CanChangeTextUsingEvent()
+ {
+ await SelectTestComponent();
+
+ var sut = Page.Locator( "#text-event-initially-blank" );
+ var textBox = sut.GetByRole( AriaRole.Textbox );
+ var result = sut.Locator( "#text-event-initially-blank-result" );
+
+ await Expect( result ).ToHaveTextAsync( string.Empty );
+
+ await textBox.FillAsync( "abcdefghijklmnopqrstuvwxyz" );
+ await Expect( result ).ToHaveTextAsync( "abcdefghijklmnopqrstuvwxyz" );
+
+ await Page.Keyboard.PressAsync( "Backspace" );
+ await Expect( result ).ToHaveTextAsync( "abcdefghijklmnopqrstuvwxy" );
+ }
+
+ [Test]
+ public async Task CanChangeTextUsingBind()
+ {
+ await SelectTestComponent();
+
+ var sut = Page.Locator( "#text-bind-initially-blank" );
+ var textBox = sut.GetByRole( AriaRole.Textbox );
+ var result = sut.Locator( "#text-bind-initially-blank-result" );
+
+ await Expect( result ).ToHaveTextAsync( string.Empty );
+
+ await textBox.FillAsync( "abcdefghijklmnopqrstuvwxyz" );
+ await Expect( result ).ToHaveTextAsync( "abcdefghijklmnopqrstuvwxyz" );
+
+ await Page.Keyboard.PressAsync( "Backspace" );
+ await Expect( result ).ToHaveTextAsync( "abcdefghijklmnopqrstuvwxy" );
+ }
+
+}
diff --git a/Tests/Blazorise.E2E.Tests/Tests/Components/TextEdit/ValidateTextEditTests.cs b/Tests/Blazorise.E2E.Tests/Tests/Components/TextEdit/ValidateTextEditTests.cs
new file mode 100644
index 0000000000..48db672d6a
--- /dev/null
+++ b/Tests/Blazorise.E2E.Tests/Tests/Components/TextEdit/ValidateTextEditTests.cs
@@ -0,0 +1,135 @@
+namespace Blazorise.E2E.Tests.Tests.Components.TextEdit;
+
+
+[Parallelizable( ParallelScope.Self )]
+[TestFixture]
+public class ValidateTextEditTests : BlazorisePageTest
+{
+ [Test]
+ public async Task CanValidateText_InitiallyBlank()
+ {
+ await SelectTestComponent();
+
+ var sut = Page.Locator( "#validate-text-initially-blank" );
+ var textBox = sut.GetByRole( AriaRole.Textbox );
+ var validationFeedback = sut.GetByText( "error" );
+
+ await ExpectTo_StartInvalid_ValidUponFill_InvalidUponClear( textBox, validationFeedback );
+ }
+
+ [Test]
+ public async Task CanValidateText_InitiallyPopulated()
+ {
+ await SelectTestComponent();
+
+ var sut = Page.Locator( "#validate-text-initially-populated" );
+ var textBox = sut.GetByRole( AriaRole.Textbox );
+ var validationFeedback = sut.GetByText( "error" );
+
+ await ExpectTo_StartValid_InvalidUponClear_ValidUponFill( textBox, validationFeedback );
+ }
+
+ [Test]
+ public async Task CanValidateTextWithBind_InitiallyBlank()
+ {
+ await SelectTestComponent();
+
+ var sut = Page.Locator( "#validate-text-with-bind-initially-blank" );
+ var textBox = sut.GetByRole( AriaRole.Textbox );
+ var validationFeedback = sut.GetByText( "error" );
+
+ await ExpectTo_StartInvalid_ValidUponFill_InvalidUponClear( textBox, validationFeedback );
+ }
+
+ [Test]
+ public async Task CanValidateTextWithBind_InitiallyPopulated()
+ {
+
+ await SelectTestComponent();
+
+ var sut = Page.Locator( "#validate-text-with-bind-initially-populated" );
+ var textBox = sut.GetByRole( AriaRole.Textbox );
+ var validationFeedback = sut.GetByText( "error" );
+
+ await ExpectTo_StartValid_InvalidUponClear_ValidUponFill( textBox, validationFeedback );
+ }
+
+ [Test]
+ public async Task CanValidateTextWithEvent_InitiallyBlank()
+ {
+ await SelectTestComponent();
+
+ var sut = Page.Locator( "#validate-text-with-event-initially-blank" );
+ var textBox = sut.GetByRole( AriaRole.Textbox );
+ var validationFeedback = sut.GetByText( "error" );
+
+ await ExpectTo_StartInvalid_ValidUponFill_InvalidUponClear( textBox, validationFeedback );
+ }
+
+ [Test]
+ public async Task CanValidateTextWithEvent_InitiallyPopulated()
+ {
+ await SelectTestComponent();
+
+ var sut = Page.Locator( "#validate-text-with-event-initially-populated" );
+ var textBox = sut.GetByRole( AriaRole.Textbox );
+ var validationFeedback = sut.GetByText( "error" );
+
+ await ExpectTo_StartValid_InvalidUponClear_ValidUponFill( textBox, validationFeedback );
+ }
+
+ [Test]
+ public async Task CanValidatePattern_InitiallyBlank()
+ {
+ await SelectTestComponent();
+
+ var sut = Page.Locator( "#validate-text-using-pattern-initially-blank" );
+ var textBox = sut.GetByRole( AriaRole.Textbox );
+ var validationFeedback = sut.GetByText( "error" );
+
+ await ExpectTo_StartInvalid_ValidUponFill_InvalidUponClear( textBox, validationFeedback );
+
+ await textBox.FillAsync( "" );
+ await textBox.FillAsync( "123" );
+ await Expect( validationFeedback ).ToHaveClassAsync( "invalid-feedback" );
+ }
+
+ [Test]
+ public async Task CanValidatePattern_InitiallyPopulated()
+ {
+ await SelectTestComponent();
+
+ var sut = Page.Locator( "#validate-text-using-pattern-initially-populated" );
+ var textBox = sut.GetByRole( AriaRole.Textbox );
+ var validationFeedback = sut.GetByText( "error" );
+
+ await ExpectTo_StartValid_InvalidUponClear_ValidUponFill( textBox, validationFeedback );
+
+ await textBox.FillAsync( "" );
+ await textBox.FillAsync( "123" );
+ await Expect( validationFeedback ).ToHaveClassAsync( "invalid-feedback" );
+ }
+
+ private async Task ExpectTo_StartInvalid_ValidUponFill_InvalidUponClear( ILocator textBox, ILocator validationFeedback )
+ {
+ await Expect( validationFeedback ).ToHaveClassAsync( "invalid-feedback" );
+
+ await textBox.FillAsync( "some text" );
+ await Expect( validationFeedback ).ToBeHiddenAsync();
+
+ await textBox.FillAsync( "" );
+ await Expect( validationFeedback ).ToHaveClassAsync( "invalid-feedback" );
+ }
+
+ private async Task ExpectTo_StartValid_InvalidUponClear_ValidUponFill( ILocator textBox, ILocator validationFeedback )
+ {
+ await Expect( validationFeedback ).ToBeHiddenAsync();
+
+ await textBox.FillAsync( "" );
+ await Expect( validationFeedback ).ToHaveClassAsync( "invalid-feedback" );
+
+ await textBox.FillAsync( "some text" );
+ await Expect( validationFeedback ).ToBeHiddenAsync();
+ }
+
+}
diff --git a/Tests/Blazorise.E2E.Tests/Tests/Components/_/ComponentRenderingTest.cs b/Tests/Blazorise.E2E.Tests/Tests/Components/_/ComponentRenderingTest.cs
new file mode 100644
index 0000000000..b9ff8f1308
--- /dev/null
+++ b/Tests/Blazorise.E2E.Tests/Tests/Components/_/ComponentRenderingTest.cs
@@ -0,0 +1,46 @@
+namespace Blazorise.E2E.Tests.Tests.Components._;
+
+[Parallelizable( ParallelScope.Self )]
+[TestFixture]
+public class ComponentRenderingTest : BlazorisePageTest
+{
+ [Test]
+ public async Task BasicTestAppCanBeServed()
+ {
+ await Page.GotoAsync( RootUri.AbsoluteUri );
+
+ await Expect( Page ).ToHaveTitleAsync( "Blazorise test app" );
+ }
+
+ [Test]
+ public async Task CanRenderTextOnlyComponent()
+ {
+ await SelectTestComponent();
+ await Expect( Page.GetByText( "Hello from TextOnlyComponent" ) ).ToBeVisibleAsync();
+ }
+
+ [Test]
+ public async Task CanRenderButtonComponent()
+ {
+ await SelectTestComponent();
+ var button = Page.GetByRole( AriaRole.Button );
+ await Expect( button ).ToHaveTextAsync( "hello primary" );
+ await Expect( button ).ToHaveClassAsync( "btn btn-primary" );
+ }
+
+ [Test]
+ public async Task CannotChangeElementId()
+ {
+ await SelectTestComponent();
+ var date = Page.GetByRole( AriaRole.Textbox );
+ var button = Page.GetByRole( AriaRole.Button );
+
+ var idBefore = await date.GetAttributeAsync( "id" );
+
+ Assert.AreNotEqual( string.Empty, idBefore );
+
+ await button.ClickAsync();
+
+ Assert.AreEqual( idBefore, await date.GetAttributeAsync( "id" ) );
+ }
+}
diff --git a/Tests/Blazorise.E2E.Tests/Usings.cs b/Tests/Blazorise.E2E.Tests/Usings.cs
new file mode 100644
index 0000000000..c54969447c
--- /dev/null
+++ b/Tests/Blazorise.E2E.Tests/Usings.cs
@@ -0,0 +1,6 @@
+global using System.Text.RegularExpressions;
+global using BasicTestApp.Client;
+global using Blazorise.E2E.Tests.Infrastructure;
+global using Microsoft.Playwright;
+global using Microsoft.Playwright.NUnit;
+global using NUnit.Framework;
diff --git a/Tests/Blazorise.E2ETests/AsyncValidateTextEditTest.cs b/Tests/Blazorise.E2ETests/AsyncValidateTextEditTest.cs
deleted file mode 100644
index 72a3850a1a..0000000000
--- a/Tests/Blazorise.E2ETests/AsyncValidateTextEditTest.cs
+++ /dev/null
@@ -1,113 +0,0 @@
-#region Using directives
-using BasicTestApp.Client;
-using Blazorise.E2ETests.Infrastructure;
-using Blazorise.E2ETests.Infrastructure.ServerFixtures;
-using OpenQA.Selenium;
-using Xunit;
-using Xunit.Abstractions;
-using DevHostServerProgram = BasicTestApp.Server.Program;
-#endregion
-
-namespace Blazorise.E2ETests;
-
-public class AsyncValidateTextEditTest : BasicTestAppTestBase
-{
- public AsyncValidateTextEditTest( BrowserFixture browserFixture,
- ToggleExecutionModeServerFixture serverFixture,
- ITestOutputHelper output )
- : base( browserFixture, serverFixture, output )
- {
- Navigate( ServerPathBase, noReload: !serverFixture.UsingAspNetHost );
- MountTestComponent();
- }
-
- [Fact]
- public void CanValidateText_InitiallyBlank()
- {
- var paragraph = Browser.FindElement( By.Id( "validate-text-initially-blank" ) );
- var edit = paragraph.FindElement( By.TagName( "input" ) );
-
- WaitAssert.True( () => paragraph.ElementIsPresent( By.ClassName( "invalid-feedback" ) ) );
-
- edit.SendKeys( "a" );
- WaitAssert.False( () => paragraph.ElementIsPresent( By.ClassName( "invalid-feedback" ) ) );
-
- edit.SendKeys( Keys.Backspace );
- WaitAssert.True( () => paragraph.ElementIsPresent( By.ClassName( "invalid-feedback" ) ) );
- }
-
- [Fact]
- public void CanValidateText_InitiallyPopulated()
- {
- var paragraph = Browser.FindElement( By.Id( "validate-text-initially-populated" ) );
- var edit = paragraph.FindElement( By.TagName( "input" ) );
-
- WaitAssert.False( () => paragraph.ElementIsPresent( By.ClassName( "invalid-feedback" ) ) );
-
- edit.SendKeys( Keys.Backspace );
- WaitAssert.True( () => paragraph.ElementIsPresent( By.ClassName( "invalid-feedback" ) ) );
-
- edit.SendKeys( "b" );
- WaitAssert.False( () => paragraph.ElementIsPresent( By.ClassName( "invalid-feedback" ) ) );
- }
-
- [Fact]
- public void CanValidateTextWithBind_InitiallyBlank()
- {
- var paragraph = Browser.FindElement( By.Id( "validate-text-with-bind-initially-blank" ) );
- var edit = paragraph.FindElement( By.TagName( "input" ) );
-
- WaitAssert.True( () => paragraph.ElementIsPresent( By.ClassName( "invalid-feedback" ) ) );
-
- edit.SendKeys( "a" );
- WaitAssert.False( () => paragraph.ElementIsPresent( By.ClassName( "invalid-feedback" ) ) );
-
- edit.SendKeys( Keys.Backspace );
- WaitAssert.True( () => paragraph.ElementIsPresent( By.ClassName( "invalid-feedback" ) ) );
- }
-
- [Fact]
- public void CanValidateTextWithBind_InitiallyPopulated()
- {
- var paragraph = Browser.FindElement( By.Id( "validate-text-with-bind-initially-populated" ) );
- var edit = paragraph.FindElement( By.TagName( "input" ) );
-
- WaitAssert.False( () => paragraph.ElementIsPresent( By.ClassName( "invalid-feedback" ) ) );
-
- edit.SendKeys( Keys.Backspace );
- WaitAssert.True( () => paragraph.ElementIsPresent( By.ClassName( "invalid-feedback" ) ) );
-
- edit.SendKeys( "b" );
- WaitAssert.False( () => paragraph.ElementIsPresent( By.ClassName( "invalid-feedback" ) ) );
- }
-
- [Fact]
- public void CanValidateTextWithEvent_InitiallyBlank()
- {
- var paragraph = Browser.FindElement( By.Id( "validate-text-with-event-initially-blank" ) );
- var edit = paragraph.FindElement( By.TagName( "input" ) );
-
- WaitAssert.True( () => paragraph.ElementIsPresent( By.ClassName( "invalid-feedback" ) ) );
-
- edit.SendKeys( "a" );
- WaitAssert.False( () => paragraph.ElementIsPresent( By.ClassName( "invalid-feedback" ) ) );
-
- edit.SendKeys( Keys.Backspace );
- WaitAssert.True( () => paragraph.ElementIsPresent( By.ClassName( "invalid-feedback" ) ) );
- }
-
- [Fact]
- public void CanValidateTextWithEvent_InitiallyPopulated()
- {
- var paragraph = Browser.FindElement( By.Id( "validate-text-with-event-initially-populated" ) );
- var edit = paragraph.FindElement( By.TagName( "input" ) );
-
- WaitAssert.False( () => paragraph.ElementIsPresent( By.ClassName( "invalid-feedback" ) ) );
-
- edit.SendKeys( Keys.Backspace );
- WaitAssert.True( () => paragraph.ElementIsPresent( By.ClassName( "invalid-feedback" ) ) );
-
- edit.SendKeys( "b" );
- WaitAssert.False( () => paragraph.ElementIsPresent( By.ClassName( "invalid-feedback" ) ) );
- }
-}
\ No newline at end of file
diff --git a/Tests/Blazorise.E2ETests/Blazorise.E2ETests.csproj b/Tests/Blazorise.E2ETests/Blazorise.E2ETests.csproj
deleted file mode 100644
index 3bb4d75c66..0000000000
--- a/Tests/Blazorise.E2ETests/Blazorise.E2ETests.csproj
+++ /dev/null
@@ -1,40 +0,0 @@
-
-
-
- net7.0
- $(DefaultItemExcludes);node_modules\**
-
- false
-
-
- true
-
- false
- 10.0
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/Tests/Blazorise.E2ETests/ButtonTest.cs b/Tests/Blazorise.E2ETests/ButtonTest.cs
deleted file mode 100644
index d4fb6b35b2..0000000000
--- a/Tests/Blazorise.E2ETests/ButtonTest.cs
+++ /dev/null
@@ -1,39 +0,0 @@
-#region Using directives
-using BasicTestApp.Client;
-using Blazorise.E2ETests.Infrastructure;
-using Blazorise.E2ETests.Infrastructure.ServerFixtures;
-using OpenQA.Selenium;
-using Xunit;
-using Xunit.Abstractions;
-using DevHostServerProgram = BasicTestApp.Server.Program;
-#endregion
-
-namespace Blazorise.E2ETests;
-
-public class ButtonTest : BasicTestAppTestBase
-{
- public ButtonTest( BrowserFixture browserFixture,
- ToggleExecutionModeServerFixture serverFixture,
- ITestOutputHelper output )
- : base( browserFixture, serverFixture, output )
- {
- Navigate( ServerPathBase, noReload: !serverFixture.UsingAspNetHost );
- MountTestComponent();
- }
-
- [Fact]
- public void CanRaiseCallback()
- {
- var paragraph = Browser.FindElement( By.Id( "basic-button-event" ) );
- var button = paragraph.FindElement( By.TagName( "button" ) );
- var result = paragraph.FindElement( By.Id( "basic-button-event-result" ) );
-
- WaitAssert.Equal( "0", () => result.Text );
-
- button.Click();
- WaitAssert.Equal( "1", () => result.Text );
-
- button.Click();
- WaitAssert.Equal( "2", () => result.Text );
- }
-}
\ No newline at end of file
diff --git a/Tests/Blazorise.E2ETests/CloseButtonTest.cs b/Tests/Blazorise.E2ETests/CloseButtonTest.cs
deleted file mode 100644
index 6625bf7183..0000000000
--- a/Tests/Blazorise.E2ETests/CloseButtonTest.cs
+++ /dev/null
@@ -1,52 +0,0 @@
-#region Using directives
-using BasicTestApp.Client;
-using Blazorise.E2ETests.Infrastructure;
-using Blazorise.E2ETests.Infrastructure.ServerFixtures;
-using OpenQA.Selenium;
-using Xunit;
-using Xunit.Abstractions;
-using DevHostServerProgram = BasicTestApp.Server.Program;
-#endregion
-
-namespace Blazorise.E2ETests;
-
-public class CloseButtonTest : BasicTestAppTestBase
-{
- public CloseButtonTest( BrowserFixture browserFixture,
- ToggleExecutionModeServerFixture serverFixture,
- ITestOutputHelper output )
- : base( browserFixture, serverFixture, output )
- {
- Navigate( ServerPathBase, noReload: !serverFixture.UsingAspNetHost );
- MountTestComponent();
- }
-
- [Fact]
- public void CanRaiseCallback()
- {
- var paragraph = Browser.FindElement( By.Id( "close-button-event" ) );
- var button = paragraph.FindElement( By.TagName( "button" ) );
- var result = paragraph.FindElement( By.Id( "close-button-event-result" ) );
-
- WaitAssert.Equal( "0", () => result.Text );
-
- button.Click();
- WaitAssert.Equal( "1", () => result.Text );
-
- button.Click();
- WaitAssert.Equal( "2", () => result.Text );
- }
-
- [Fact]
- public void CanAutoClose()
- {
- var paragraph = Browser.FindElement( By.Id( "autoclose-button-event" ) );
- var button = paragraph.FindElement( By.Id( "autoclose-button" ) );
- var result = paragraph.FindElement( By.Id( "autoclose-button-event-result" ) );
-
- WaitAssert.Equal( "0", () => result.Text );
-
- button.Click();
- WaitAssert.Equal( "1", () => result.Text );
- }
-}
\ No newline at end of file
diff --git a/Tests/Blazorise.E2ETests/ComponentRenderingTest.cs b/Tests/Blazorise.E2ETests/ComponentRenderingTest.cs
deleted file mode 100644
index b6fc94c2b2..0000000000
--- a/Tests/Blazorise.E2ETests/ComponentRenderingTest.cs
+++ /dev/null
@@ -1,59 +0,0 @@
-#region Using directives
-using BasicTestApp.Client;
-using Blazorise.E2ETests.Infrastructure;
-using Blazorise.E2ETests.Infrastructure.ServerFixtures;
-using OpenQA.Selenium;
-using Xunit;
-using Xunit.Abstractions;
-using DevHostServerProgram = BasicTestApp.Server.Program;
-#endregion
-
-namespace Blazorise.E2ETests;
-
-public class ComponentRenderingTest : BasicTestAppTestBase
-{
- public ComponentRenderingTest( BrowserFixture browserFixture,
- ToggleExecutionModeServerFixture serverFixture,
- ITestOutputHelper output )
- : base( browserFixture, serverFixture, output )
- {
- Navigate( ServerPathBase, noReload: !serverFixture.UsingAspNetHost );
- }
-
- [Fact]
- public void BasicTestAppCanBeServed()
- {
- Assert.Equal( "Blazorise test app", Browser.Title );
- }
-
- [Fact]
- public void CanRenderTextOnlyComponent()
- {
- var appElement = MountTestComponent();
- Assert.Equal( "Hello from TextOnlyComponent", appElement.Text );
- }
-
- [Fact]
- public void CanRenderButtonComponent()
- {
- var appElement = MountTestComponent();
- var btnElement = appElement.FindElement( By.TagName( "button" ) );
- Assert.Equal( "hello primary", btnElement.Text );
- Assert.Equal( "btn btn-primary", btnElement.GetAttribute( "class" ) );
- }
-
- [Fact]
- public void CannotChangeElementId()
- {
- var appElement = MountTestComponent();
- var date = appElement.FindElement( By.TagName( "input" ) );
- var button = appElement.FindElement( By.TagName( "button" ) );
-
- Assert.NotEqual( string.Empty, date.GetAttribute( "id" ) );
-
- var before = date.GetAttribute( "id" );
-
- button.Click();
- WaitAssert.Equal( before, () => date.GetAttribute( "id" ) );
- }
-}
\ No newline at end of file
diff --git a/Tests/Blazorise.E2ETests/DateEditTest.cs b/Tests/Blazorise.E2ETests/DateEditTest.cs
deleted file mode 100644
index b12bda052c..0000000000
--- a/Tests/Blazorise.E2ETests/DateEditTest.cs
+++ /dev/null
@@ -1,41 +0,0 @@
-//#region Using directives
-//using BasicTestApp.Client;
-//using Blazorise.E2ETests.Infrastructure;
-//using Blazorise.E2ETests.Infrastructure.ServerFixtures;
-//using OpenQA.Selenium;
-//using OpenQA.Selenium.Support.UI;
-//using Xunit;
-//using Xunit.Abstractions;
-//using DevHostServerProgram = BasicTestApp.Server.Program;
-//#endregion
-
-//namespace Blazorise.E2ETests
-//{
-// public class DateEditTest : BasicTestAppTestBase
-// {
-// public DateEditTest( BrowserFixture browserFixture,
-// ToggleExecutionModeServerFixture serverFixture,
-// ITestOutputHelper output )
-// : base( browserFixture, serverFixture, output )
-// {
-// Navigate( ServerPathBase, noReload: !serverFixture.UsingAspNetHost );
-// MountTestComponent();
-// }
-
-// [Fact]
-// public void CanChangeUndefinedIntegerUsingEvent()
-// {
-// var paragraph = Browser.FindElement( By.Id( "date-event-initially-undefined" ) );
-// var date = paragraph.FindElement( By.TagName( "input" ) );
-// var result = paragraph.FindElement( By.Id( "date-event-initially-undefined-result" ) );
-
-// WaitAssert.Equal( "0001-01-01", () => result.Text );
-
-// date.SendKeysSequentially( "662021" );
-// WaitAssert.Equal( "2021-06-06", () => result.Text );
-
-// date.SendKeys( Keys.Backspace );
-// WaitAssert.Equal( "0001-01-01", () => result.Text );
-// }
-// }
-//}
diff --git a/Tests/Blazorise.E2ETests/DropdownTest.cs b/Tests/Blazorise.E2ETests/DropdownTest.cs
deleted file mode 100644
index 5aee792959..0000000000
--- a/Tests/Blazorise.E2ETests/DropdownTest.cs
+++ /dev/null
@@ -1,40 +0,0 @@
-#region Using directives
-using BasicTestApp.Client;
-using Blazorise.E2ETests.Infrastructure;
-using Blazorise.E2ETests.Infrastructure.ServerFixtures;
-using OpenQA.Selenium;
-using Xunit;
-using Xunit.Abstractions;
-using DevHostServerProgram = BasicTestApp.Server.Program;
-#endregion
-
-namespace Blazorise.E2ETests;
-
-public class DropdownTest : BasicTestAppTestBase
-{
- public DropdownTest( BrowserFixture browserFixture,
- ToggleExecutionModeServerFixture serverFixture,
- ITestOutputHelper output )
- : base( browserFixture, serverFixture, output )
- {
- Navigate( ServerPathBase, noReload: !serverFixture.UsingAspNetHost );
- MountTestComponent();
- }
-
- [Fact]
- public void CanShowAndHideDropdownComponent()
- {
- var appElement = MountTestComponent();
- var drpElement = appElement.FindElement( By.ClassName( "dropdown" ) );
- var btnElement = drpElement.FindElement( By.TagName( "button" ) );
- var mnuElement = drpElement.FindElement( By.ClassName( "dropdown-menu" ) );
-
- btnElement.Click();
- WaitAssert.Contains( "show", () => drpElement.GetAttribute( "class" ) );
- WaitAssert.Contains( "show", () => mnuElement.GetAttribute( "class" ) );
-
- btnElement.Click();
- WaitAssert.NotContains( "show", () => drpElement.GetAttribute( "class" ) );
- WaitAssert.NotContains( "show", () => mnuElement.GetAttribute( "class" ) );
- }
-}
\ No newline at end of file
diff --git a/Tests/Blazorise.E2ETests/Infrastructure/BasicTestAppTestBase.cs b/Tests/Blazorise.E2ETests/Infrastructure/BasicTestAppTestBase.cs
deleted file mode 100644
index efec56e059..0000000000
--- a/Tests/Blazorise.E2ETests/Infrastructure/BasicTestAppTestBase.cs
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright (c) .NET Foundation. All rights reserved.
-// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-
-using Microsoft.AspNetCore.Components;
-using Blazorise.E2ETests.Infrastructure.ServerFixtures;
-using OpenQA.Selenium;
-using OpenQA.Selenium.Support.UI;
-using System;
-using Xunit.Abstractions;
-using BasicTestApp.Server;
-
-namespace Blazorise.E2ETests.Infrastructure;
-
-public class BasicTestAppTestBase : ServerTestBase>
-{
- public string ServerPathBase
- => "/subdir" + ( _serverFixture.UsingAspNetHost ? "#server" : "" );
-
- public BasicTestAppTestBase(
- BrowserFixture browserFixture,
- ToggleExecutionModeServerFixture serverFixture,
- ITestOutputHelper output )
- : base( browserFixture, serverFixture, output )
- {
- serverFixture.PathBase = ServerPathBase;
- }
-
- protected IWebElement MountTestComponent() where TComponent : IComponent
- {
- var componentTypeName = typeof( TComponent ).FullName;
- var testSelector = WaitUntilTestSelectorReady();
- testSelector.SelectByValue( "none" );
- testSelector.SelectByValue( componentTypeName );
- return Browser.FindElement( By.TagName( "app" ) );
- }
-
- protected SelectElement WaitUntilTestSelectorReady()
- {
- var elemToFind = By.CssSelector( "#test-selector > select" );
- new WebDriverWait( Browser, TimeSpan.FromSeconds( 30 ) ).Until(
- driver => driver.FindElement( elemToFind ) != null );
- return new( Browser.FindElement( elemToFind ) );
- }
-}
\ No newline at end of file
diff --git a/Tests/Blazorise.E2ETests/Infrastructure/BrowserFixture.cs b/Tests/Blazorise.E2ETests/Infrastructure/BrowserFixture.cs
deleted file mode 100644
index 48dfb6b8fa..0000000000
--- a/Tests/Blazorise.E2ETests/Infrastructure/BrowserFixture.cs
+++ /dev/null
@@ -1,59 +0,0 @@
-// Copyright (c) .NET Foundation. All rights reserved.
-// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-
-using OpenQA.Selenium;
-using OpenQA.Selenium.Chrome;
-using OpenQA.Selenium.Remote;
-using System;
-using Xunit.Abstractions;
-
-namespace Blazorise.E2ETests.Infrastructure;
-
-public class BrowserFixture : IDisposable
-{
- public IWebDriver Browser { get; }
-
- public ILogs Logs { get; }
-
- public ITestOutputHelper Output { get; set; }
-
- public BrowserFixture()
- {
- var opts = new ChromeOptions();
-
- // Comment this out if you want to watch or interact with the browser (e.g., for debugging)
- opts.AddArgument( "--headless" );
-
- // Log errors
- opts.SetLoggingPreference( LogType.Browser, LogLevel.All );
-
- // On Windows/Linux, we don't need to set opts.BinaryLocation
- // But for Travis Mac builds we do
- var binaryLocation = Environment.GetEnvironmentVariable( "TEST_CHROME_BINARY" );
- if ( !string.IsNullOrEmpty( binaryLocation ) )
- {
- opts.BinaryLocation = binaryLocation;
- Console.WriteLine( $"Set {nameof( ChromeOptions )}.{nameof( opts.BinaryLocation )} to {binaryLocation}" );
- }
-
- try
- {
- var driver = new RemoteWebDriver( SeleniumStandaloneServer.Instance.Uri, opts );
- driver.Manage().Timeouts().ImplicitWait = TimeSpan.FromSeconds( 1 );
- Browser = driver;
- Logs = new RemoteLogs( driver );
- }
- catch ( WebDriverException ex )
- {
- var message =
- "Failed to connect to the web driver. Please see the readme and follow the instructions to install selenium." +
- "Remember to start the web driver with `selenium-standalone start` before running the end-to-end tests.";
- throw new InvalidOperationException( message, ex );
- }
- }
-
- public void Dispose()
- {
- Browser.Dispose();
- }
-}
\ No newline at end of file
diff --git a/Tests/Blazorise.E2ETests/Infrastructure/BrowserTestBase.cs b/Tests/Blazorise.E2ETests/Infrastructure/BrowserTestBase.cs
deleted file mode 100644
index 005ef5c6a3..0000000000
--- a/Tests/Blazorise.E2ETests/Infrastructure/BrowserTestBase.cs
+++ /dev/null
@@ -1,30 +0,0 @@
-// Copyright (c) .NET Foundation. All rights reserved.
-// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-
-using System.Threading;
-using OpenQA.Selenium;
-using Xunit;
-using Xunit.Abstractions;
-
-namespace Blazorise.E2ETests.Infrastructure;
-
-[CaptureSeleniumLogs]
-public class BrowserTestBase : IClassFixture
-{
- private static readonly AsyncLocal _browser = new();
- private static readonly AsyncLocal _logs = new();
- private static readonly AsyncLocal _output = new();
-
- public static IWebDriver Browser => _browser.Value;
-
- public static ILogs Logs => _logs.Value;
-
- public static ITestOutputHelper Output => _output.Value;
-
- public BrowserTestBase( BrowserFixture browserFixture, ITestOutputHelper output )
- {
- _browser.Value = browserFixture.Browser;
- _logs.Value = browserFixture.Logs;
- _output.Value = output;
- }
-}
\ No newline at end of file
diff --git a/Tests/Blazorise.E2ETests/Infrastructure/CaptureSeleniumLogsAttribute.cs b/Tests/Blazorise.E2ETests/Infrastructure/CaptureSeleniumLogsAttribute.cs
deleted file mode 100644
index 0074562aed..0000000000
--- a/Tests/Blazorise.E2ETests/Infrastructure/CaptureSeleniumLogsAttribute.cs
+++ /dev/null
@@ -1,47 +0,0 @@
-// Copyright (c) .NET Foundation. All rights reserved.
-// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-
-
-using System;
-using System.Linq;
-using System.Reflection;
-using OpenQA.Selenium;
-using Xunit.Sdk;
-
-namespace Blazorise.E2ETests.Infrastructure;
-
-// This has to use BeforeAfterTestAttribute because running the log capture
-// in the BrowserFixture.Dispose method is too late, and we can't add logging
-// to the test.
-public class CaptureSeleniumLogsAttribute : BeforeAfterTestAttribute
-{
- public override void Before( MethodInfo methodUnderTest )
- {
- if ( !typeof( BrowserTestBase ).IsAssignableFrom( methodUnderTest.DeclaringType ) )
- {
- throw new InvalidOperationException( "This should only be used with BrowserTestBase" );
- }
- }
-
- public override void After( MethodInfo methodUnderTest )
- {
- var logs = BrowserTestBase.Logs;
- var output = BrowserTestBase.Output;
-
- // Put browser logs first, the test UI will truncate output after a certain length
- // and the browser logs will include exceptions thrown by js in the browser.
- foreach ( var kind in logs.AvailableLogTypes.OrderBy( k => k == LogType.Browser ? 0 : 1 ) )
- {
- output.WriteLine( $"{kind} Logs from Selenium:" );
-
- var entries = logs.GetLog( kind );
- foreach ( LogEntry entry in entries )
- {
- output.WriteLine( $"[{entry.Timestamp}] - {entry.Level} - {entry.Message}" );
- }
-
- output.WriteLine( "" );
- output.WriteLine( "" );
- }
- }
-}
\ No newline at end of file
diff --git a/Tests/Blazorise.E2ETests/Infrastructure/Extensions.cs b/Tests/Blazorise.E2ETests/Infrastructure/Extensions.cs
deleted file mode 100644
index aef92ff979..0000000000
--- a/Tests/Blazorise.E2ETests/Infrastructure/Extensions.cs
+++ /dev/null
@@ -1,15 +0,0 @@
-using System;
-using System.Threading.Tasks;
-
-namespace Blazorise.E2ETests.Infrastructure;
-
-public static class Extensions
-{
- public static async Task TimeoutAfter( this Task task, TimeSpan timeSpan )
- {
- if ( task == await Task.WhenAny( task, Task.Delay( timeSpan ) ) )
- await task;
- else
- throw new TimeoutException();
- }
-}
\ No newline at end of file
diff --git a/Tests/Blazorise.E2ETests/Infrastructure/ProcessExtensions.cs b/Tests/Blazorise.E2ETests/Infrastructure/ProcessExtensions.cs
deleted file mode 100644
index be326119b9..0000000000
--- a/Tests/Blazorise.E2ETests/Infrastructure/ProcessExtensions.cs
+++ /dev/null
@@ -1,100 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.IO;
-using System.Runtime.InteropServices;
-
-namespace Blazorise.E2ETests.Infrastructure;
-
-internal static class ProcessExtensions
-{
- private static readonly bool _isWindows = RuntimeInformation.IsOSPlatform( OSPlatform.Windows );
- private static readonly TimeSpan _defaultTimeout = TimeSpan.FromSeconds( 30 );
-
- public static void KillTree( this Process process, TimeSpan timeout )
- {
- var pid = process.Id;
- if ( _isWindows )
- {
- RunProcessAndWaitForExit(
- "taskkill",
- $"/T /F /PID {pid}",
- timeout,
- out _ );
- }
- else
- {
- var children = new HashSet();
- GetAllChildIdsUnix( pid, children, timeout );
- foreach ( var childId in children )
- {
- KillProcessUnix( childId, timeout );
- }
- KillProcessUnix( pid, timeout );
- }
- }
-
- private static void GetAllChildIdsUnix( int parentId, ISet children, TimeSpan timeout )
- {
- RunProcessAndWaitForExit(
- "pgrep",
- $"-P {parentId}",
- timeout,
- out var stdout );
-
- if ( !string.IsNullOrEmpty( stdout ) )
- {
- using ( var reader = new StringReader( stdout ) )
- {
- while ( true )
- {
- var text = reader.ReadLine();
- if ( text == null )
- {
- return;
- }
-
- if ( int.TryParse( text, out var id ) )
- {
- children.Add( id );
- // Recursively get the children
- GetAllChildIdsUnix( id, children, timeout );
- }
- }
- }
- }
- }
-
- private static void KillProcessUnix( int processId, TimeSpan timeout )
- {
- RunProcessAndWaitForExit(
- "kill",
- $"-TERM {processId}",
- timeout,
- out string _ );
- }
-
- private static void RunProcessAndWaitForExit( string fileName, string arguments, TimeSpan timeout, out string stdout )
- {
- var startInfo = new ProcessStartInfo
- {
- FileName = fileName,
- Arguments = arguments,
- RedirectStandardOutput = true,
- RedirectStandardError = true,
- UseShellExecute = false,
- };
-
- var process = Process.Start( startInfo );
-
- stdout = null;
- if ( process.WaitForExit( (int)timeout.TotalMilliseconds ) )
- {
- stdout = process.StandardOutput.ReadToEnd();
- }
- else
- {
- process.Kill();
- }
- }
-}
\ No newline at end of file
diff --git a/Tests/Blazorise.E2ETests/Infrastructure/SeleniumStandaloneServer.cs b/Tests/Blazorise.E2ETests/Infrastructure/SeleniumStandaloneServer.cs
deleted file mode 100644
index f1105433a4..0000000000
--- a/Tests/Blazorise.E2ETests/Infrastructure/SeleniumStandaloneServer.cs
+++ /dev/null
@@ -1,140 +0,0 @@
-// Copyright (c) .NET Foundation. All rights reserved.
-// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-
-using System;
-using System.Diagnostics;
-using System.Net;
-using System.Net.Http;
-using System.Net.Sockets;
-using System.Runtime.InteropServices;
-using System.Text;
-using System.Threading.Tasks;
-//using Microsoft.AspNetCore.Testing;
-
-namespace Blazorise.E2ETests.Infrastructure;
-
-class SeleniumStandaloneServer
-{
- private static readonly TimeSpan Timeout = TimeSpan.FromSeconds( 30 );
- private static readonly object _instanceCreationLock = new();
- private static SeleniumStandaloneServer _instance;
-
- public Uri Uri { get; }
-
- public static SeleniumStandaloneServer Instance
- {
- get
- {
- lock ( _instanceCreationLock )
- {
- _instance ??= new();
- }
-
- return _instance;
- }
- }
-
- private SeleniumStandaloneServer()
- {
- var port = FindAvailablePort();
- Uri = new UriBuilder( "http", "localhost", port, "/wd/hub" ).Uri;
-
- var psi = new ProcessStartInfo
- {
- FileName = "npm",
- Arguments = $"run selenium-standalone start -- -- -port {port}",
- RedirectStandardOutput = true,
- RedirectStandardError = true,
- };
-
- if ( RuntimeInformation.IsOSPlatform( OSPlatform.Windows ) )
- {
- psi.FileName = "cmd";
- psi.Arguments = $"/c npm {psi.Arguments}";
- }
-
- var process = Process.Start( psi );
-
- var builder = new StringBuilder();
- process.OutputDataReceived += LogOutput;
- process.ErrorDataReceived += LogOutput;
-
- process.BeginOutputReadLine();
- process.BeginErrorReadLine();
-
- // The Selenium sever has to be up for the entirety of the tests and is only shutdown when the application (i.e. the test) exits.
- AppDomain.CurrentDomain.ProcessExit += ( _, _ ) =>
- {
- if ( !process.HasExited )
- {
- process.KillTree( TimeSpan.FromSeconds( 10 ) );
- process.Dispose();
- }
- };
-
- void LogOutput( object sender, DataReceivedEventArgs e )
- {
- lock ( builder )
- {
- builder.AppendLine( e.Data );
- }
- }
-
- var waitForStart = Task.Run( async () =>
- {
- using var httpClient = new HttpClient
- {
- Timeout = TimeSpan.FromSeconds( 1 ),
- };
-
- while ( true )
- {
- try
- {
- var responseTask = httpClient.GetAsync( Uri );
-
- var response = await responseTask;
- if ( response.StatusCode == HttpStatusCode.OK )
- {
- return;
- }
- }
- catch ( OperationCanceledException )
- {
-
- }
- await Task.Delay( 1000 );
- }
- } );
-
- try
- {
- waitForStart.TimeoutAfter( Timeout ).Wait( 1000 );
- }
- catch ( Exception ex )
- {
- string output;
- lock ( builder )
- {
- output = builder.ToString();
- }
-
- throw new InvalidOperationException( $"Failed to start selenium sever. {Environment.NewLine}{output}", ex.GetBaseException() );
- }
- }
-
- static int FindAvailablePort()
- {
- var listener = new TcpListener( IPAddress.Loopback, 0 );
-
- try
- {
- listener.Start();
- return ( (IPEndPoint)listener.LocalEndpoint ).Port;
- }
- finally
- {
- listener.Stop();
- }
- }
-}
\ No newline at end of file
diff --git a/Tests/Blazorise.E2ETests/Infrastructure/ServerFixtures/AspNetEnvironment.cs b/Tests/Blazorise.E2ETests/Infrastructure/ServerFixtures/AspNetEnvironment.cs
deleted file mode 100644
index 0a66abf036..0000000000
--- a/Tests/Blazorise.E2ETests/Infrastructure/ServerFixtures/AspNetEnvironment.cs
+++ /dev/null
@@ -1,10 +0,0 @@
-// Copyright (c) .NET Foundation. All rights reserved.
-// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-
-namespace Blazorise.E2ETests.Infrastructure.ServerFixtures;
-
-public enum AspNetEnvironment
-{
- Development,
- Production
-}
\ No newline at end of file
diff --git a/Tests/Blazorise.E2ETests/Infrastructure/ServerFixtures/AspNetSiteServerFixture.cs b/Tests/Blazorise.E2ETests/Infrastructure/ServerFixtures/AspNetSiteServerFixture.cs
deleted file mode 100644
index a2528efef2..0000000000
--- a/Tests/Blazorise.E2ETests/Infrastructure/ServerFixtures/AspNetSiteServerFixture.cs
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright (c) .NET Foundation. All rights reserved.
-// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-
-using System;
-using Microsoft.AspNetCore.Hosting;
-
-namespace Blazorise.E2ETests.Infrastructure.ServerFixtures;
-
-public class AspNetSiteServerFixture : WebHostServerFixture
-{
- public delegate IWebHost BuildWebHost( string[] args );
-
- public BuildWebHost BuildWebHostMethod { get; set; }
-
- public AspNetEnvironment Environment { get; set; } = AspNetEnvironment.Production;
-
- protected override IWebHost CreateWebHost()
- {
- if ( BuildWebHostMethod == null )
- {
- throw new InvalidOperationException(
- $"No value was provided for {nameof( BuildWebHostMethod )}" );
- }
-
- var sampleSitePath = FindSampleOrTestSitePath(
- BuildWebHostMethod.Method.DeclaringType!.Assembly.GetName().Name );
-
- return BuildWebHostMethod( new[]
- {
- "--urls", "http://127.0.0.1:0",
- "--contentroot", sampleSitePath,
- "--environment", Environment.ToString(),
- } );
- }
-}
\ No newline at end of file
diff --git a/Tests/Blazorise.E2ETests/Infrastructure/ServerFixtures/DevHostServerFixture.cs b/Tests/Blazorise.E2ETests/Infrastructure/ServerFixtures/DevHostServerFixture.cs
deleted file mode 100644
index 124d0d8fa6..0000000000
--- a/Tests/Blazorise.E2ETests/Infrastructure/ServerFixtures/DevHostServerFixture.cs
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright (c) .NET Foundation. All rights reserved.
-// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-
-using Microsoft.AspNetCore.Hosting;
-using System.Collections.Generic;
-using DevHostServerProgram = BasicTestApp.Server.Program;
-
-namespace Blazorise.E2ETests.Infrastructure.ServerFixtures;
-
-public class DevHostServerFixture : WebHostServerFixture
-{
- public string Environment { get; set; }
- public string PathBase { get; set; }
- public string ContentRoot { get; private set; }
-
- protected override IWebHost CreateWebHost()
- {
- ContentRoot = FindSampleOrTestSitePath( typeof( TProgram ).Assembly.GetName().Name );
-
- var args = new List
- {
- "--urls", "http://127.0.0.1:0",
- "--contentroot", ContentRoot,
- "--pathbase", PathBase
- };
-
- if ( !string.IsNullOrEmpty( Environment ) )
- {
- args.Add( "--environment" );
- args.Add( Environment );
- }
-
- return DevHostServerProgram.BuildWebHost( args.ToArray() );
- }
-}
\ No newline at end of file
diff --git a/Tests/Blazorise.E2ETests/Infrastructure/ServerFixtures/ServerFixture.cs b/Tests/Blazorise.E2ETests/Infrastructure/ServerFixtures/ServerFixture.cs
deleted file mode 100644
index cf79837374..0000000000
--- a/Tests/Blazorise.E2ETests/Infrastructure/ServerFixtures/ServerFixture.cs
+++ /dev/null
@@ -1,89 +0,0 @@
-// Copyright (c) .NET Foundation. All rights reserved.
-// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using System.Threading;
-
-namespace Blazorise.E2ETests.Infrastructure.ServerFixtures;
-
-public abstract class ServerFixture : IDisposable
-{
- private static readonly Lazy> _projects = new( FindProjects );
-
- public Uri RootUri => _rootUriInitializer.Value;
-
- private readonly Lazy _rootUriInitializer;
-
- public ServerFixture()
- {
- _rootUriInitializer = new( () =>
- new( StartAndGetRootUri() ) );
- }
-
- public abstract void Dispose();
-
- protected abstract string StartAndGetRootUri();
-
- protected static string FindSolutionDir()
- {
- return FindClosestDirectoryContaining(
- "Blazorise.sln",
- Path.GetDirectoryName( typeof( ServerFixture ).Assembly.Location ) );
- }
-
- private static Dictionary FindProjects()
- {
- var solutionDir = FindSolutionDir();
- return Directory.GetFiles( solutionDir, "*.csproj", SearchOption.AllDirectories )
- .ToDictionary( Path.GetFileNameWithoutExtension, Path.GetDirectoryName );
- }
-
- protected static string FindSampleOrTestSitePath( string projectName )
- {
- var projects = _projects.Value;
- if ( projects.TryGetValue( projectName, out var dir ) )
- {
- return dir;
- }
-
- throw new ArgumentException( $"Cannot find a sample or test site with name '{projectName}'." );
- }
-
- private static string FindClosestDirectoryContaining(
- string filename,
- string startDirectory )
- {
- var dir = startDirectory;
- while ( true )
- {
- if ( File.Exists( Path.Combine( dir, filename ) ) )
- {
- return dir;
- }
-
- dir = Directory.GetParent( dir )?.FullName;
- if ( string.IsNullOrEmpty( dir ) )
- {
- throw new FileNotFoundException(
- $"Could not locate a file called '{filename}' in " +
- $"directory '{startDirectory}' or any parent directory." );
- }
- }
- }
-
- protected static void RunInBackgroundThread( Action action )
- {
- var isDone = new ManualResetEvent( false );
-
- new Thread( () =>
- {
- action();
- isDone.Set();
- } ).Start();
-
- isDone.WaitOne();
- }
-}
\ No newline at end of file
diff --git a/Tests/Blazorise.E2ETests/Infrastructure/ServerFixtures/StaticSiteServerFixture.cs b/Tests/Blazorise.E2ETests/Infrastructure/ServerFixtures/StaticSiteServerFixture.cs
deleted file mode 100644
index d9b17eba65..0000000000
--- a/Tests/Blazorise.E2ETests/Infrastructure/ServerFixtures/StaticSiteServerFixture.cs
+++ /dev/null
@@ -1,42 +0,0 @@
-// Copyright (c) .NET Foundation. All rights reserved.
-// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-
-using System;
-using Microsoft.AspNetCore.Builder;
-using Microsoft.AspNetCore.Hosting;
-
-namespace Blazorise.E2ETests.Infrastructure.ServerFixtures;
-// Although this is not used for anything meaningful related to Blazor yet, it
-// will be used later when there's a mechanism for publishing standalone Blazor
-// apps as a set of purely static files and we need E2E testing on the result.
-
-public class StaticSiteServerFixture : WebHostServerFixture
-{
- public string SampleSiteName { get; set; }
-
- protected override IWebHost CreateWebHost()
- {
- if ( string.IsNullOrEmpty( SampleSiteName ) )
- {
- throw new InvalidOperationException( $"No value was provided for {nameof( SampleSiteName )}" );
- }
-
- var sampleSitePath = FindSampleOrTestSitePath( SampleSiteName );
-
- return new WebHostBuilder()
- .UseKestrel()
- .UseContentRoot( sampleSitePath )
- .UseWebRoot( string.Empty )
- .UseStartup()
- .UseUrls( "http://127.0.0.1:0" )
- .Build();
- }
-
- private class StaticSiteStartup
- {
- public void Configure( IApplicationBuilder app )
- {
- app.UseFileServer();
- }
- }
-}
\ No newline at end of file
diff --git a/Tests/Blazorise.E2ETests/Infrastructure/ServerFixtures/ToggleExecutionModeServerFixture.cs b/Tests/Blazorise.E2ETests/Infrastructure/ServerFixtures/ToggleExecutionModeServerFixture.cs
deleted file mode 100644
index c80b234324..0000000000
--- a/Tests/Blazorise.E2ETests/Infrastructure/ServerFixtures/ToggleExecutionModeServerFixture.cs
+++ /dev/null
@@ -1,48 +0,0 @@
-// Copyright (c) .NET Foundation. All rights reserved.
-// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-
-using System;
-
-namespace Blazorise.E2ETests.Infrastructure.ServerFixtures;
-
-public class ToggleExecutionModeServerFixture
- : ServerFixture
-{
- public string PathBase { get; set; }
- public bool UsingAspNetHost { get; private set; }
-
- private AspNetSiteServerFixture.BuildWebHost _buildWebHostMethod;
- private IDisposable _serverToDispose;
-
- public void UseAspNetHost( AspNetSiteServerFixture.BuildWebHost buildWebHostMethod )
- {
- _buildWebHostMethod = buildWebHostMethod
- ?? throw new ArgumentNullException( nameof( buildWebHostMethod ) );
- UsingAspNetHost = true;
- }
-
- protected override string StartAndGetRootUri()
- {
- if ( _buildWebHostMethod == null )
- {
- // Use Blazor's dev host server
- var underlying = new DevHostServerFixture();
- underlying.PathBase = PathBase;
- _serverToDispose = underlying;
- return underlying.RootUri.AbsoluteUri;
- }
- else
- {
- // Use specified ASP.NET host server
- var underlying = new AspNetSiteServerFixture();
- underlying.BuildWebHostMethod = _buildWebHostMethod;
- _serverToDispose = underlying;
- return underlying.RootUri.AbsoluteUri;
- }
- }
-
- public override void Dispose()
- {
- _serverToDispose?.Dispose();
- }
-}
\ No newline at end of file
diff --git a/Tests/Blazorise.E2ETests/Infrastructure/ServerFixtures/WebHostServerFixture.cs b/Tests/Blazorise.E2ETests/Infrastructure/ServerFixtures/WebHostServerFixture.cs
deleted file mode 100644
index e93c6ad12e..0000000000
--- a/Tests/Blazorise.E2ETests/Infrastructure/ServerFixtures/WebHostServerFixture.cs
+++ /dev/null
@@ -1,31 +0,0 @@
-// Copyright (c) .NET Foundation. All rights reserved.
-// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-
-using Microsoft.AspNetCore.Hosting;
-using Microsoft.AspNetCore.Hosting.Server.Features;
-using System.Linq;
-
-namespace Blazorise.E2ETests.Infrastructure.ServerFixtures;
-
-public abstract class WebHostServerFixture : ServerFixture
-{
- private IWebHost _host;
-
- protected override string StartAndGetRootUri()
- {
- _host = CreateWebHost();
- RunInBackgroundThread( _host.Start );
- return _host.ServerFeatures
- .Get()
- .Addresses.Single();
- }
-
- public override void Dispose()
- {
- // This can be null if creating the webhost throws, we don't want to throw here and hide
- // the original exception.
- _host?.StopAsync();
- }
-
- protected abstract IWebHost CreateWebHost();
-}
\ No newline at end of file
diff --git a/Tests/Blazorise.E2ETests/Infrastructure/ServerTestBase.cs b/Tests/Blazorise.E2ETests/Infrastructure/ServerTestBase.cs
deleted file mode 100644
index c7a36d46ee..0000000000
--- a/Tests/Blazorise.E2ETests/Infrastructure/ServerTestBase.cs
+++ /dev/null
@@ -1,39 +0,0 @@
-// Copyright (c) .NET Foundation. All rights reserved.
-// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-
-using Blazorise.E2ETests.Infrastructure.ServerFixtures;
-using System;
-using Xunit;
-using Xunit.Abstractions;
-
-namespace Blazorise.E2ETests.Infrastructure;
-
-public abstract class ServerTestBase
- : BrowserTestBase, IClassFixture
- where TServerFixture : ServerFixture
-{
- protected readonly TServerFixture _serverFixture;
-
- public ServerTestBase( BrowserFixture browserFixture, TServerFixture serverFixture, ITestOutputHelper output )
- : base( browserFixture, output )
- {
- _serverFixture = serverFixture;
- }
-
- public void Navigate( string relativeUrl, bool noReload = false )
- {
- var absoluteUrl = new Uri( _serverFixture.RootUri, relativeUrl );
-
- if ( noReload )
- {
- var existingUrl = Browser.Url;
- if ( string.Equals( existingUrl, absoluteUrl.AbsoluteUri, StringComparison.Ordinal ) )
- {
- return;
- }
- }
-
- Browser.Navigate().GoToUrl( "about:blank" );
- Browser.Navigate().GoToUrl( absoluteUrl );
- }
-}
\ No newline at end of file
diff --git a/Tests/Blazorise.E2ETests/Infrastructure/WaitAssert.cs b/Tests/Blazorise.E2ETests/Infrastructure/WaitAssert.cs
deleted file mode 100644
index ecbe6a18a4..0000000000
--- a/Tests/Blazorise.E2ETests/Infrastructure/WaitAssert.cs
+++ /dev/null
@@ -1,82 +0,0 @@
-// Copyright (c) .NET Foundation. All rights reserved.
-// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
-
-using System;
-using System.Collections;
-using System.Collections.Generic;
-using OpenQA.Selenium;
-using OpenQA.Selenium.Support.UI;
-using Xunit;
-
-namespace Blazorise.E2ETests.Infrastructure;
-// XUnit assertions, but hooked into Selenium's polling mechanism
-
-public class WaitAssert
-{
- private readonly static TimeSpan DefaultTimeout = TimeSpan.FromSeconds( 3 );
-
- public static void Equal( T expected, Func actual )
- => WaitAssertCore( () => Assert.Equal( expected, actual() ) );
-
- public static void NotEqual( T expected, Func actual )
- => WaitAssertCore( () => Assert.NotEqual( expected, actual() ) );
-
- public static void True( Func actual )
- => WaitAssertCore( () => Assert.True( actual() ) );
-
- public static void True( Func actual, TimeSpan timeout )
- => WaitAssertCore( () => Assert.True( actual() ), timeout );
-
- public static void False( Func actual )
- => WaitAssertCore( () => Assert.False( actual() ) );
-
- public static void Contains( string expectedSubstring, Func actualString )
- => WaitAssertCore( () => Assert.Contains( expectedSubstring, actualString() ) );
-
- public static void NotContains( string expectedSubstring, Func actualString )
- => WaitAssertCore( () => Assert.DoesNotContain( expectedSubstring, actualString() ) );
-
- public static void Collection( Func> actualValues, params Action[] elementInspectors )
- => WaitAssertCore( () => Assert.Collection( actualValues(), elementInspectors ) );
-
- public static void Empty( Func actualValues )
- => WaitAssertCore( () => Assert.Empty( actualValues() ) );
-
- public static void Single( Func actualValues )
- => WaitAssertCore( () => Assert.Single( actualValues() ) );
-
- public static void Null( Func