From 4d7d351422f92b30919a209abdd3c2169d6134a4 Mon Sep 17 00:00:00 2001 From: StuartFerguson Date: Sun, 21 Jun 2026 08:45:21 +0100 Subject: [PATCH 01/17] add BDD dashboard integration testing with Playwright - Add Reqnroll-based dashboard integration scenarios - Wire up Playwright browser automation - Update dashboard helpers and step definitions - Add test-friendly app startup/config changes - Improve dashboard auth and rendering traces for debugging --- .github/workflows/pullrequest.yml | 98 +- {Pages => Archive/Pages}/_Host.cshtml | 0 Directory.Packages.props | 16 +- .../Components/Pages/EntryScreen.razor | 2 +- .../Components/Pages/Home.razor.cs | 42 +- .../Permissions/AuthorizedComponentBase.cs | 18 +- EstateManagementUI.BlazorServer/Dockerfile | 1 + .../Dockerfile.original | 38 + .../EstateManagementUI.BlazorServer.csproj | 1 + .../appsettings.Development.json | 20 +- .../Common/ContractManagementPageHelper.cs | 661 ---------- .../Common/DashboardPageHelper.cs | 411 +++--- .../Common/DockerHelper.cs | 691 ++++++++++ .../Common/EstateManagementPageHelper.cs | 486 ------- .../Common/MerchantManagementPageHelper.cs | 1114 ----------------- .../Common/OperatorManagementPageHelper.cs | 556 -------- .../Common/ReportingPageHelper.cs | 703 ----------- ...EstateManagementUI.IntegrationTests.csproj | 13 +- .../Features/ContractManagement.feature | 186 --- .../Features/Dashboard.feature | 156 +-- .../Features/EstateManagement.feature | 153 --- .../Features/MerchantManagement.feature | 367 ------ .../Features/OperatorManagement.feature | 172 --- .../Features/Reporting.feature | 372 ------ .../Hooks/BrowserHooks.cs | 102 +- .../Steps/BackgroundSteps.cs | 213 ++++ .../Steps/ContractManagementSteps.cs | 449 ------- .../Steps/DashboardSteps.cs | 186 +-- .../Steps/EstateManagementSteps.cs | 290 ----- .../Steps/MerchantManagementSteps.cs | 638 ---------- .../Steps/OperatorManagementSteps.cs | 342 ----- .../Steps/ReportingSteps.cs | 618 --------- ...estdiag.host.26-06-19_13-41-30_03760_5.txt | 742 +++++++++++ .../testdiag.txt | 755 +++++++++++ 34 files changed, 3043 insertions(+), 7569 deletions(-) rename {Pages => Archive/Pages}/_Host.cshtml (100%) create mode 100644 EstateManagementUI.BlazorServer/Dockerfile.original delete mode 100644 EstateManagementUI.IntegrationTests/Common/ContractManagementPageHelper.cs create mode 100644 EstateManagementUI.IntegrationTests/Common/DockerHelper.cs delete mode 100644 EstateManagementUI.IntegrationTests/Common/EstateManagementPageHelper.cs delete mode 100644 EstateManagementUI.IntegrationTests/Common/MerchantManagementPageHelper.cs delete mode 100644 EstateManagementUI.IntegrationTests/Common/OperatorManagementPageHelper.cs delete mode 100644 EstateManagementUI.IntegrationTests/Common/ReportingPageHelper.cs delete mode 100644 EstateManagementUI.IntegrationTests/Features/ContractManagement.feature delete mode 100644 EstateManagementUI.IntegrationTests/Features/EstateManagement.feature delete mode 100644 EstateManagementUI.IntegrationTests/Features/MerchantManagement.feature delete mode 100644 EstateManagementUI.IntegrationTests/Features/OperatorManagement.feature delete mode 100644 EstateManagementUI.IntegrationTests/Features/Reporting.feature create mode 100644 EstateManagementUI.IntegrationTests/Steps/BackgroundSteps.cs delete mode 100644 EstateManagementUI.IntegrationTests/Steps/ContractManagementSteps.cs delete mode 100644 EstateManagementUI.IntegrationTests/Steps/EstateManagementSteps.cs delete mode 100644 EstateManagementUI.IntegrationTests/Steps/MerchantManagementSteps.cs delete mode 100644 EstateManagementUI.IntegrationTests/Steps/OperatorManagementSteps.cs delete mode 100644 EstateManagementUI.IntegrationTests/Steps/ReportingSteps.cs create mode 100644 EstateManagementUI.IntegrationTests/testdiag.host.26-06-19_13-41-30_03760_5.txt create mode 100644 EstateManagementUI.IntegrationTests/testdiag.txt diff --git a/.github/workflows/pullrequest.yml b/.github/workflows/pullrequest.yml index 3ae1d185..29f36e39 100644 --- a/.github/workflows/pullrequest.yml +++ b/.github/workflows/pullrequest.yml @@ -50,59 +50,59 @@ jobs: retention-days: 30 -# chrometests: -# name: "Build and Test UI - Chrome" -# env: -# ASPNETCORE_ENVIRONMENT: "Production" -# NODE_VERSION: '14.x' # set this to the node version to use - -# runs-on: ubuntu-latest - -# steps: -# - uses: actions/checkout@v2.3.4 - -# - name: Trust Certificate -# run: | -# sudo apt-get install expect -# certPath="$GITHUB_WORKSPACE/Certificates/aspnetapp-root-cert.pfx" -# password="password" - -# # Use expect to automate the passphrase input -# expect -c " -# spawn openssl pkcs12 -in \"$certPath\" -clcerts -nokeys -out certificate.crt -password pass:\"$password\" -# expect \"Enter Import Password:\" { send \"$password\n\" } -# expect eof -# " - -# expect -c " -# spawn openssl pkcs12 -in \"$certPath\" -nocerts -out private.key -password pass:\"$password\" -# expect \"Enter Import Password:\" { send \"$password\n\" } -# expect eof -# " - -# sudo cp certificate.crt /usr/local/share/ca-certificates/aspnetapp-root-cert.crt -# sudo update-ca-certificates - -# sudo cp private.key /etc/ssl/private/aspnetapp-root-cert.key -# sudo chmod 400 /etc/ssl/private/aspnetapp-root-cert.key + chrometests: + name: "Build and Test UI - Chrome" + env: + ASPNETCORE_ENVIRONMENT: "Production" + NODE_VERSION: '14.x' # set this to the node version to use + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2.3.4 + + - name: Trust Certificate + run: | + sudo apt-get install expect + certPath="$GITHUB_WORKSPACE/Certificates/aspnetapp-root-cert.pfx" + password="password" + + # Use expect to automate the passphrase input + expect -c " + spawn openssl pkcs12 -in \"$certPath\" -clcerts -nokeys -out certificate.crt -password pass:\"$password\" + expect \"Enter Import Password:\" { send \"$password\n\" } + expect eof + " + + expect -c " + spawn openssl pkcs12 -in \"$certPath\" -nocerts -out private.key -password pass:\"$password\" + expect \"Enter Import Password:\" { send \"$password\n\" } + expect eof + " + + sudo cp certificate.crt /usr/local/share/ca-certificates/aspnetapp-root-cert.crt + sudo update-ca-certificates + + sudo cp private.key /etc/ssl/private/aspnetapp-root-cert.key + sudo chmod 400 /etc/ssl/private/aspnetapp-root-cert.key -# - name: Build Docker Image -# run: docker build . --file EstateManagementUI/Dockerfile --tag estatemanagementui:latest + - name: Build Docker Image + run: docker build . --file EstateManagementUI/Dockerfile --tag estatemanagementui:latest -# - name: Restore Nuget Packages -# run: dotnet restore EstateManagementUI.sln --source ${{ secrets.PUBLICFEEDURL }} --source ${{ secrets.PRIVATEFEED_URL }} + - name: Restore Nuget Packages + run: dotnet restore EstateManagementUI.sln --source ${{ secrets.PUBLICFEEDURL }} --source ${{ secrets.PRIVATEFEED_URL }} -# - name: Run Integration Tests (Chrome) -# env: -# Browser: Chrome -# IsCI: true -# run: dotnet test "EstateManagementUI.IntegrationTests\EstateManagementUI.IntegrationTests.csproj" --filter Category=PRTest + - name: Run Integration Tests (Chrome) + env: + Browser: Chrome + IsCI: true + run: dotnet test "EstateManagementUI.IntegrationTests\EstateManagementUI.IntegrationTests.csproj" # --filter Category=PRTest -# - uses: actions/upload-artifact@v4.4.0 -# if: ${{ failure() }} -# with: -# name: chrometracelogs -# path: /home/txnproc/trace/ + - uses: actions/upload-artifact@v4.4.0 + if: ${{ failure() }} + with: + name: chrometracelogs + path: /home/txnproc/trace/ # edgetests: # name: "Build and Test UI - Edge" diff --git a/Pages/_Host.cshtml b/Archive/Pages/_Host.cshtml similarity index 100% rename from Pages/_Host.cshtml rename to Archive/Pages/_Host.cshtml diff --git a/Directory.Packages.props b/Directory.Packages.props index 3e5fab83..24bfe947 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -4,9 +4,9 @@ - + - + @@ -14,11 +14,14 @@ + + + @@ -27,12 +30,15 @@ + - - + + + - + + diff --git a/EstateManagementUI.BlazorServer/Components/Pages/EntryScreen.razor b/EstateManagementUI.BlazorServer/Components/Pages/EntryScreen.razor index 11bc4f01..f00bc25e 100644 --- a/EstateManagementUI.BlazorServer/Components/Pages/EntryScreen.razor +++ b/EstateManagementUI.BlazorServer/Components/Pages/EntryScreen.razor @@ -131,7 +131,7 @@

Sign in to access all features

- + diff --git a/EstateManagementUI.BlazorServer/Components/Pages/Home.razor.cs b/EstateManagementUI.BlazorServer/Components/Pages/Home.razor.cs index 770920aa..749044b7 100644 --- a/EstateManagementUI.BlazorServer/Components/Pages/Home.razor.cs +++ b/EstateManagementUI.BlazorServer/Components/Pages/Home.razor.cs @@ -34,16 +34,22 @@ protected override async Task OnAfterRenderAsync(bool firstRender) } // This runs once after the interactive circuit is established. - await this.LogToConsole("OnAfterRenderAsync FIRST RENDER (interactive) - performing interactive initialization"); + await this.TraceDashboardAsync("OnAfterRenderAsync FIRST RENDER - starting interactive initialization"); + await this.TraceDashboardAsync($"Current URI: {NavigationManager.Uri}"); try { - await OnAfterRender(PermissionSection.Dashboard, PermissionFunction.View); + var permissionResult = await OnAfterRender(PermissionSection.Dashboard, PermissionFunction.View); + await this.TraceDashboardAsync($"Dashboard permission check result: {(permissionResult.IsFailed ? "FAILED" : "SUCCESS")}"); + ClaimsPrincipal user = this.AuthState.User; + await this.TraceDashboardAsync($"Authentication state: authenticated={user.Identity?.IsAuthenticated}, name={user.Identity?.Name ?? ""}, authType={user.Identity?.AuthenticationType ?? ""}"); + await this.TraceDashboardAsync($"Claims: {string.Join(", ", user.Claims.Select(c => $"{c.Type}={c.Value}"))}"); // Redirect unauthenticated users to entry screen if (!user.Identity?.IsAuthenticated ?? true) { + await this.TraceDashboardAsync("User is not authenticated - redirecting to entry page"); NavigationManager.NavigateToEntryPage(); return; } @@ -51,29 +57,33 @@ protected override async Task OnAfterRenderAsync(bool firstRender) // Determine role and admin flag now that we're interactive var role = await PermissionService.GetUserRoleAsync(); this.isAdministrator = role == "Administrator"; - await this.LogToConsole($"User role: {role}, isAdministrator: {this.isAdministrator}"); - - CorrelationId correlationId = new CorrelationId(Guid.NewGuid()); - var estateId = await this.GetEstateId(); + await this.TraceDashboardAsync($"User role resolved to '{role}', isAdministrator={this.isAdministrator}"); // Only load dashboard data for non-admins if (this.isAdministrator == false) { + CorrelationId correlationId = new CorrelationId(Guid.NewGuid()); + var estateId = await this.GetEstateId(); + await this.TraceDashboardAsync($"Resolved estateId for dashboard data load: {estateId}"); + await this.TraceDashboardAsync("Non-admin user - loading dashboard data"); var result = await this.LoadDashboardData(correlationId, estateId); if (result.IsFailed) { + await this.TraceDashboardAsync($"Dashboard data load failed: {result.Message ?? ""}"); this.NavigationManager.NavigateToErrorPage(); return; } } else { + await this.TraceDashboardAsync("Administrator detected - skipping dashboard data load and rendering welcome panel"); this.isLoading = false; this.StateHasChanged(); } } catch (Exception ex) { + await this.TraceDashboardAsync($"Initialization exception: {ex}"); this.errorMessage = $"Initialization error: {ex.Message}"; this.isLoading = false; this.StateHasChanged(); @@ -86,7 +96,7 @@ protected override async Task OnAfterRenderAsync(bool firstRender) private async Task LoadDashboardData(CorrelationId correlationId, Guid estateId) { - await this.LogToConsole($"LoadDashboardData START - selectedDate: {this._selectedComparisonDate}"); + await this.TraceDashboardAsync($"LoadDashboardData START - selectedDate: {this._selectedComparisonDate}"); try { this.isLoading = true; this.errorMessage = null; @@ -142,8 +152,10 @@ private async Task LoadDashboardData(CorrelationId correlationId, Guid e private async Task> LoadComparisonDates(CorrelationId correlationId, Guid estateId) { if (this.comparisonDates == null || !this.comparisonDates.Any()) { + await this.TraceDashboardAsync($"Loading comparison dates for estateId={estateId}"); var comparisonDatesResult = await this.CalendarUiService.GetComparisonDates(correlationId, estateId); if (comparisonDatesResult.IsFailed) { + await this.TraceDashboardAsync($"Comparison dates load failed: {comparisonDatesResult.Message ?? ""}"); return ResultHelpers.CreateFailure(comparisonDatesResult); } @@ -165,7 +177,7 @@ private async Task> LoadComparisonDates(CorrelationId correlati private async Task OnComparisonDateChanged() { this.changeEventCounter++; - await this.LogToConsole($"🔥 OnComparisonDateChanged FIRED! Count: {this.changeEventCounter}, New value: {this._selectedComparisonDate}"); + await this.TraceDashboardAsync($"OnComparisonDateChanged fired. Count={this.changeEventCounter}, New value={this._selectedComparisonDate}"); // This is called after _selectedComparisonDate is updated by @bind-Value if (this.isAdministrator == false) { @@ -173,20 +185,28 @@ private async Task OnComparisonDateChanged() CorrelationId correlationId = CorrelationIdHelper.New(); Guid estateId= await this.GetEstateId(); - await this.LogToConsole($"Loading dashboard data for date: {this._selectedComparisonDate}"); + await this.TraceDashboardAsync($"Loading dashboard data for date: {this._selectedComparisonDate}"); var loadResult = await this.LoadDashboardData(correlationId,estateId); if (loadResult.IsFailed) { + await this.TraceDashboardAsync($"Dashboard refresh failed: {loadResult.Message ?? ""}"); this.NavigationManager.NavigateToErrorPage(); return; } this.StateHasChanged(); - await this.LogToConsole("Dashboard data reload complete"); + await this.TraceDashboardAsync("Dashboard data reload complete"); } else { - await this.LogToConsole("User is administrator - skipping data reload"); + await this.TraceDashboardAsync("Administrator user - skipping dashboard data reload"); } } + private async Task TraceDashboardAsync(string message) + { + var trace = $"[Home.razor {DateTime.Now:HH:mm:ss.fff}] {message}"; + Console.WriteLine(trace); + await this.LogToConsole(message); + } + private async Task LogToConsole(string message) { try diff --git a/EstateManagementUI.BlazorServer/Components/Permissions/AuthorizedComponentBase.cs b/EstateManagementUI.BlazorServer/Components/Permissions/AuthorizedComponentBase.cs index de7b2188..78a29254 100644 --- a/EstateManagementUI.BlazorServer/Components/Permissions/AuthorizedComponentBase.cs +++ b/EstateManagementUI.BlazorServer/Components/Permissions/AuthorizedComponentBase.cs @@ -25,8 +25,10 @@ protected async Task RequirePermission(PermissionSection permissionSecti { // Do a permission check here Boolean hasPermission = await this.PermissionService.HasPermissionAsync(permissionSection, permissionFunction); + Console.WriteLine($"[AuthorizedComponentBase {DateTime.Now:HH:mm:ss.fff}] RequirePermission section={permissionSection}, function={permissionFunction}, result={hasPermission}"); if (hasPermission == false) { + Console.WriteLine($"[AuthorizedComponentBase {DateTime.Now:HH:mm:ss.fff}] Permission denied - navigating to access denied page"); this.NavigationManager.NavigateToAccessDeniedPage(); return Result.Unauthorized(); } @@ -37,8 +39,13 @@ protected async Task RequirePermission(PermissionSection permissionSecti protected async Task GetEstateId() { Result estateIdResult = this.AuthState.GetEstateIdFromClaims(); if (estateIdResult.IsFailed) { + Console.WriteLine($"[AuthorizedComponentBase {DateTime.Now:HH:mm:ss.fff}] Failed to resolve estateId from claims"); this.NavigationManager.NavigateToErrorPage(); } + else + { + Console.WriteLine($"[AuthorizedComponentBase {DateTime.Now:HH:mm:ss.fff}] Resolved estateId={estateIdResult.Data}"); + } return estateIdResult.Data; } @@ -52,20 +59,29 @@ protected async Task OnAfterRender(PermissionSection section, { this.AuthState = await AuthenticationStateTask; User = this.AuthState.User; + Console.WriteLine($"[AuthorizedComponentBase {DateTime.Now:HH:mm:ss.fff}] OnAfterRender authState authenticated={User.Identity?.IsAuthenticated}, name={User.Identity?.Name ?? ""}, authType={User.Identity?.AuthenticationType ?? ""}, claims={string.Join(", ", User.Claims.Select(c => $"{c.Type}={c.Value}"))}"); Result authResult = await RequirePermission(section, function); if (authResult.IsFailed) + { + Console.WriteLine($"[AuthorizedComponentBase {DateTime.Now:HH:mm:ss.fff}] OnAfterRender stopped because permission check failed"); return Result.Failure(); + } if (loadFunc == null) + { + Console.WriteLine($"[AuthorizedComponentBase {DateTime.Now:HH:mm:ss.fff}] OnAfterRender completed without loadFunc"); return Result.Success(); + } Result result = await loadFunc(); if (result.IsFailed) { + Console.WriteLine($"[AuthorizedComponentBase {DateTime.Now:HH:mm:ss.fff}] OnAfterRender loadFunc failed"); this.NavigationManager.NavigateToErrorPage(); return Result.Failure(); } + Console.WriteLine($"[AuthorizedComponentBase {DateTime.Now:HH:mm:ss.fff}] OnAfterRender loadFunc succeeded"); return Result.Success(); } -} \ No newline at end of file +} diff --git a/EstateManagementUI.BlazorServer/Dockerfile b/EstateManagementUI.BlazorServer/Dockerfile index 993d3bb2..4b6de0eb 100644 --- a/EstateManagementUI.BlazorServer/Dockerfile +++ b/EstateManagementUI.BlazorServer/Dockerfile @@ -13,6 +13,7 @@ RUN curl -fsSL --insecure https://deb.nodesource.com/setup_20.x | bash - && \ COPY ["EstateManagementUI.BlazorServer/NuGet.Config", "."] COPY ["EstateManagementUI.BlazorServer/Certificates/*.*", "Certificates/"] COPY ["EstateManagementUI.BlazorServer/EstateManagementUI.BlazorServer.csproj", "EstateManagementUI.BlazorServer/"] +COPY ["Directory.Packages.props", "."] RUN dotnet restore "./EstateManagementUI.BlazorServer/EstateManagementUI.BlazorServer.csproj" COPY . . diff --git a/EstateManagementUI.BlazorServer/Dockerfile.original b/EstateManagementUI.BlazorServer/Dockerfile.original new file mode 100644 index 00000000..993d3bb2 --- /dev/null +++ b/EstateManagementUI.BlazorServer/Dockerfile.original @@ -0,0 +1,38 @@ +FROM stuartferguson/txnprocbase AS base +WORKDIR /app + +# This stage is used to build the service project +FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build +ARG BUILD_CONFIGURATION=Release +WORKDIR /src + +# Install Node.js for Tailwind CSS build - use insecure curl for corporate proxy environments +RUN curl -fsSL --insecure https://deb.nodesource.com/setup_20.x | bash - && \ + apt-get install -y nodejs + +COPY ["EstateManagementUI.BlazorServer/NuGet.Config", "."] +COPY ["EstateManagementUI.BlazorServer/Certificates/*.*", "Certificates/"] +COPY ["EstateManagementUI.BlazorServer/EstateManagementUI.BlazorServer.csproj", "EstateManagementUI.BlazorServer/"] +RUN dotnet restore "./EstateManagementUI.BlazorServer/EstateManagementUI.BlazorServer.csproj" + +COPY . . +WORKDIR "/src/EstateManagementUI.BlazorServer" + +# Install npm packages and build Tailwind CSS +RUN npm install +RUN npm run css:build + +RUN dotnet build "./EstateManagementUI.BlazorServer.csproj" -c $BUILD_CONFIGURATION -o /app/build + +# This stage is used to publish the service project to be copied to the final stage +FROM build AS publish +ARG BUILD_CONFIGURATION=Release +RUN dotnet publish "./EstateManagementUI.BlazorServer.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false + +# This stage is used in production or when running from VS in regular mode (Default when not using the Debug configuration) +FROM base AS final +WORKDIR /app +COPY --from=publish /app/publish . +# Copy certificates to the runtime image +COPY --from=build /src/EstateManagementUI.BlazorServer/Certificates ./Certificates +ENTRYPOINT ["dotnet", "EstateManagementUI.BlazorServer.dll"] diff --git a/EstateManagementUI.BlazorServer/EstateManagementUI.BlazorServer.csproj b/EstateManagementUI.BlazorServer/EstateManagementUI.BlazorServer.csproj index 15ec8ff7..10e4ef21 100644 --- a/EstateManagementUI.BlazorServer/EstateManagementUI.BlazorServer.csproj +++ b/EstateManagementUI.BlazorServer/EstateManagementUI.BlazorServer.csproj @@ -18,6 +18,7 @@ + diff --git a/EstateManagementUI.BlazorServer/appsettings.Development.json b/EstateManagementUI.BlazorServer/appsettings.Development.json index d4c5b89f..5a5cda7a 100644 --- a/EstateManagementUI.BlazorServer/appsettings.Development.json +++ b/EstateManagementUI.BlazorServer/appsettings.Development.json @@ -11,20 +11,20 @@ "SecurityServicePort": null, "HttpClientIgnoreCertificateErrors": true, "TestMode": "Disabled", - //"TransactionProcessorApi": "http://192.168.1.163:5002", - //"EstateReportingApi": "http://192.168.1.163:5011", - //"FileProcessorApi": "http://192.168.1.163:5009", - //"SecurityService": "https://192.168.1.163:5001", - "TransactionProcessorApi": "http://127.0.0.1:5002", - "EstateReportingApi": "http://127.0.0.1:5011", - "FileProcessorApi": "http://127.0.0.1:5009", - "SecurityService": "https://127.0.0.1:5001", + "TransactionProcessorApi": "http://192.168.1.163:5002", + "EstateReportingApi": "http://192.168.1.163:5011", + "FileProcessorApi": "http://192.168.1.163:5009", + "SecurityService": "https://192.168.1.163:5001", + //"TransactionProcessorApi": "http://127.0.0.1:5002", + //"EstateReportingApi": "http://127.0.0.1:5011", + //"FileProcessorApi": "http://127.0.0.1:5009", + //"SecurityService": "https://127.0.0.1:5001", "ClientId": "serviceClient", "ClientSecret": "d192cbc46d834d0da90e8a9d50ded543" }, "Authentication": { - "Authority": "https://127.0.0.1:5001", - //"Authority": "https://192.168.1.163:5001", + //"Authority": "https://127.0.0.1:5001", + "Authority": "https://192.168.1.163:5001", "ClientId": "managementUIClient", "ClientSecret": "d192cbc46d834d0da90e8a9d50ded543", "CallbackPath": "/signin-oidc", diff --git a/EstateManagementUI.IntegrationTests/Common/ContractManagementPageHelper.cs b/EstateManagementUI.IntegrationTests/Common/ContractManagementPageHelper.cs deleted file mode 100644 index ec922780..00000000 --- a/EstateManagementUI.IntegrationTests/Common/ContractManagementPageHelper.cs +++ /dev/null @@ -1,661 +0,0 @@ -using Microsoft.Playwright; -using Shouldly; - -namespace EstateManagementUI.IntegrationTests.Common; - -/// -/// Helper class for interacting with the Contract Management pages using Playwright -/// -public class ContractManagementPageHelper -{ - private readonly IPage _page; - private readonly string _baseUrl; - - public ContractManagementPageHelper(IPage page, string baseUrl) - { - _page = page; - _baseUrl = baseUrl; - } - - #region Navigation - - /// - /// Navigate to the Contract Management page (index) - /// - public async Task NavigateToContractManagement() - { - await _page.GotoAsync($"{_baseUrl}/contracts"); - await _page.WaitForLoadStateAsync(LoadState.NetworkIdle); - } - - /// - /// Navigate to home page to check menu visibility - /// - public async Task NavigateToHome() - { - await _page.GotoAsync(_baseUrl); - await _page.WaitForLoadStateAsync(LoadState.NetworkIdle); - } - - /// - /// Navigate to the Create New Contract page - /// - public async Task NavigateToCreateNewContract() - { - await _page.GotoAsync($"{_baseUrl}/contracts/new"); - await _page.WaitForLoadStateAsync(LoadState.NetworkIdle); - } - - /// - /// Navigate to the Edit Contract page for a specific contract - /// - public async Task NavigateToEditContract(string contractId) - { - await _page.GotoAsync($"{_baseUrl}/contracts/{contractId}/edit"); - await _page.WaitForLoadStateAsync(LoadState.NetworkIdle); - } - - /// - /// Navigate to the Edit Contract page for the first contract (using hardcoded test data ID) - /// - public async Task NavigateToEditFirstContract() - { - // Using the hardcoded test data contract ID from StubbedMediatorService - await NavigateToEditContract("44444444-4444-4444-4444-444444444444"); - } - - #endregion - - #region Menu Visibility Verification - - /// - /// Verify that Contract Management menu is not visible (Administrator role) - /// - public async Task VerifyContractManagementMenuIsNotVisible() - { - // Wait for page to be in stable state - await _page.WaitForLoadStateAsync(LoadState.NetworkIdle); - - var menuLinkCount = await _page.Locator("text=Contract Management").CountAsync(); - menuLinkCount.ShouldBe(0, "Contract Management menu should not be visible for Administrator role"); - } - - /// - /// Verify that Contract Management menu is visible - /// - public async Task VerifyContractManagementMenuIsVisible() - { - await _page.Locator("text=Contract Management").WaitForAsync(); - var menuLinkCount = await _page.Locator("text=Contract Management").CountAsync(); - menuLinkCount.ShouldBeGreaterThan(0, "Contract Management menu should be visible"); - } - - #endregion - - #region Page Verification - - /// - /// Verify the Contract Management page is displayed - /// - public async Task VerifyContractManagementPageIsDisplayed() - { - await _page.Locator("h1:has-text('Contract Management')").WaitForAsync(); - var heading = await _page.Locator("h1:has-text('Contract Management')").TextContentAsync(); - heading.ShouldNotBeNull(); - heading.ShouldContain("Contract Management"); - } - - /// - /// Verify the page title - /// - public async Task VerifyPageTitle(string expectedTitle) - { - var title = await _page.TitleAsync(); - title.ShouldBe(expectedTitle); - } - - /// - /// Verify the View Contract page is displayed - /// - public async Task VerifyViewContractPageIsDisplayed() - { - await _page.Locator("h1:has-text('View Contract')").WaitForAsync(); - var heading = await _page.Locator("h1").TextContentAsync(); - heading.ShouldNotBeNull(); - heading.ShouldContain("View Contract"); - } - - /// - /// Verify the Create New Contract page is displayed - /// - public async Task VerifyCreateNewContractPageIsDisplayed() - { - await _page.Locator("h1:has-text('Create New Contract')").WaitForAsync(); - var heading = await _page.Locator("h1:has-text('Create New Contract')").TextContentAsync(); - heading.ShouldNotBeNull(); - heading.ShouldContain("Create New Contract"); - } - - /// - /// Verify the Edit Contract page is displayed - /// - public async Task VerifyEditContractPageIsDisplayed() - { - await _page.Locator("h1:has-text('Edit Contract')").WaitForAsync(); - var heading = await _page.Locator("h1").TextContentAsync(); - heading.ShouldNotBeNull(); - heading.ShouldContain("Edit Contract"); - } - - /// - /// Verify access denied message is displayed - /// - public async Task VerifyAccessDeniedMessageIsDisplayed() - { - await _page.Locator("h3:has-text('Access Denied')").WaitForAsync(); - var message = await _page.Locator("h3:has-text('Access Denied')").TextContentAsync(); - message.ShouldNotBeNull(); - message.ShouldContain("Access Denied"); - } - - /// - /// Verify access denied message for contract creation - /// - public async Task VerifyAccessDeniedForContractCreation() - { - await _page.Locator("text=You don't have permission to create contracts").WaitForAsync(); - } - - /// - /// Verify access denied message for contract editing - /// - public async Task VerifyAccessDeniedForContractEditing() - { - await _page.Locator("text=You don't have permission to edit contracts").WaitForAsync(); - } - - #endregion - - #region Contract List Verification - - /// - /// Verify the number of contracts displayed in the list - /// - public async Task VerifyContractCount(int expectedCount) - { - // Wait for contracts grid to be present - await _page.WaitForLoadStateAsync(LoadState.NetworkIdle); - - var contractCards = _page.Locator(".bg-white.rounded-lg.shadow-md.p-6.hover\\:shadow-lg"); - var count = await contractCards.CountAsync(); - count.ShouldBe(expectedCount, $"Expected {expectedCount} contracts but found {count}"); - } - - /// - /// Verify the "Add New Contract" button is visible - /// - public async Task VerifyAddNewContractButtonIsVisible() - { - await _page.Locator("#newContractButton").WaitForAsync(); - var button = await _page.Locator("#newContractButton").IsVisibleAsync(); - button.ShouldBeTrue("Add New Contract button should be visible"); - } - - /// - /// Verify the "Add New Contract" button is not visible - /// - public async Task VerifyAddNewContractButtonIsNotVisible() - { - await _page.WaitForLoadStateAsync(LoadState.NetworkIdle); - var buttonCount = await _page.Locator("#newContractButton").CountAsync(); - buttonCount.ShouldBe(0, "Add New Contract button should not be visible"); - } - - /// - /// Verify Edit button is not visible for contracts (Viewer role) - /// - public async Task VerifyEditButtonIsNotVisibleForContracts() - { - await _page.WaitForLoadStateAsync(LoadState.NetworkIdle); - var editButtonCount = await _page.Locator("button:has-text('Edit')").CountAsync(); - editButtonCount.ShouldBe(0, "Edit button should not be visible for contracts"); - } - - #endregion - - #region Contract Details Verification - - /// - /// Verify contract description on view page - /// - public async Task VerifyContractDescription(string expectedDescription) - { - var descriptionElement = _page.Locator("p.text-gray-900.font-medium").First; - var description = await descriptionElement.TextContentAsync(); - description.ShouldNotBeNull(); - description.Trim().ShouldBe(expectedDescription); - } - - /// - /// Verify contract operator on view page - /// - public async Task VerifyContractOperator(string expectedOperator) - { - var operatorElements = _page.Locator("p.text-gray-900.font-medium"); - var operatorText = await operatorElements.Nth(1).TextContentAsync(); - operatorText.ShouldNotBeNull(); - operatorText.Trim().ShouldBe(expectedOperator); - } - - /// - /// Verify the number of products in a contract - /// - public async Task VerifyContractProductCount(int expectedCount) - { - var productCards = _page.Locator(".border.border-gray-200.rounded-lg.p-4"); - var count = await productCards.CountAsync(); - count.ShouldBe(expectedCount, $"Expected {expectedCount} products but found {count}"); - } - - /// - /// Verify the first product name - /// - public async Task VerifyFirstProductName(string expectedName) - { - var productNameElement = _page.Locator("h4.text-md.font-semibold.text-gray-900").First; - var productName = await productNameElement.TextContentAsync(); - productName.ShouldNotBeNull(); - productName.Trim().ShouldBe(expectedName); - } - - /// - /// Verify the number of transaction fees for the first product - /// - public async Task VerifyFirstProductTransactionFeeCount(int expectedCount) - { - var feeCards = _page.Locator(".bg-gray-50.rounded.p-3"); - var count = await feeCards.CountAsync(); - count.ShouldBe(expectedCount, $"Expected {expectedCount} transaction fees but found {count}"); - } - - /// - /// Verify a specific transaction fee exists with expected value - /// - public async Task VerifyProductTransactionFee(string productName, string feeDescription, string expectedValue) - { - var feeCard = _page.Locator($".bg-gray-50.rounded.p-3:has-text('{feeDescription}')"); - await feeCard.WaitForAsync(); - - var feeText = await feeCard.TextContentAsync(); - feeText.ShouldNotBeNull(); - feeText.ShouldContain(feeDescription); - feeText.ShouldContain(expectedValue); - } - - #endregion - - #region Form Verification - - /// - /// Verify the contract form is displayed - /// - public async Task VerifyContractFormIsDisplayed() - { - await _page.Locator("form").WaitForAsync(); - var form = await _page.Locator("form").IsVisibleAsync(); - form.ShouldBeTrue("Contract form should be displayed"); - } - - /// - /// Verify a specific field is visible - /// - public async Task VerifyFieldIsVisible(string fieldLabel) - { - var field = _page.Locator($"label:has-text('{fieldLabel}')"); - await field.WaitForAsync(); - var isVisible = await field.IsVisibleAsync(); - isVisible.ShouldBeTrue($"{fieldLabel} field should be visible"); - } - - /// - /// Verify description field contains specific value on edit page - /// - public async Task VerifyDescriptionFieldContains(string expectedValue) - { - var descriptionInput = _page.Locator("input[type='text']").First; - var value = await descriptionInput.InputValueAsync(); - value.ShouldBe(expectedValue); - } - - /// - /// Verify operator name is displayed on edit page - /// - public async Task VerifyOperatorNameDisplayed(string expectedOperator) - { - var operatorText = await _page.Locator("p.text-gray-900.font-medium").First.TextContentAsync(); - operatorText.ShouldNotBeNull(); - operatorText.Trim().ShouldBe(expectedOperator); - } - - /// - /// Verify products section is displayed on edit page - /// - public async Task VerifyProductsSectionIsDisplayed() - { - await _page.Locator("h3:has-text('Products')").WaitForAsync(); - } - - /// - /// Verify the number of products listed on edit page - /// - public async Task VerifyProductCountOnEditPage(int expectedCount) - { - var productCards = _page.Locator(".border.border-gray-200.rounded-lg.p-4"); - var count = await productCards.CountAsync(); - count.ShouldBe(expectedCount, $"Expected {expectedCount} products but found {count}"); - } - - /// - /// Verify Add Product button is visible - /// - public async Task VerifyAddProductButtonIsVisible() - { - var button = _page.Locator("button:has-text('Add Product')"); - await button.WaitForAsync(); - var isVisible = await button.IsVisibleAsync(); - isVisible.ShouldBeTrue("Add Product button should be visible"); - } - - /// - /// Verify validation errors are displayed - /// - public async Task VerifyValidationErrorsAreDisplayed() - { - var errors = _page.Locator(".text-red-600.text-sm"); - var count = await errors.CountAsync(); - count.ShouldBeGreaterThan(0, "Validation errors should be displayed"); - } - - /// - /// Verify specific validation error is shown - /// - public async Task VerifyValidationErrorMessage(string errorMessage) - { - await _page.Locator($"text={errorMessage}").WaitForAsync(); - } - - #endregion - - #region Interaction Methods - - /// - /// Click on View button for the first contract - /// - public async Task ClickViewButtonForFirstContract() - { - var viewButton = _page.Locator("button:has-text('View')").First; - await viewButton.ClickAsync(); - await _page.WaitForLoadStateAsync(LoadState.NetworkIdle); - } - - /// - /// Click on Edit button for the first contract - /// - public async Task ClickEditButtonForFirstContract() - { - var editButton = _page.Locator("button:has-text('Edit')").First; - await editButton.ClickAsync(); - await _page.WaitForLoadStateAsync(LoadState.NetworkIdle); - } - - /// - /// Click on Add New Contract button - /// - public async Task ClickAddNewContractButton() - { - await _page.Locator("#newContractButton").ClickAsync(); - await _page.WaitForLoadStateAsync(LoadState.NetworkIdle); - } - - /// - /// Enter text in a form field - /// - public async Task EnterTextInField(string fieldLabel, string text) - { - // Find the input associated with the label - var input = _page.Locator($"label:has-text('{fieldLabel}')").Locator("..").Locator("input"); - await input.FillAsync(text); - } - - /// - /// Select an option from a dropdown - /// - public async Task SelectFromDropdown(string fieldLabel, string option) - { - var select = _page.Locator($"label:has-text('{fieldLabel}')").Locator("..").Locator("select"); - await select.SelectOptionAsync(new[] { option }); - } - - /// - /// Click on a button by its text or ID - /// - public async Task ClickButton(string buttonText) - { - var button = _page.Locator($"button:has-text('{buttonText}')").First; - await button.ClickAsync(); - await Task.Delay(500); // Wait for any state changes - } - - /// - /// Click on Create Contract button (with ID) - /// - public async Task ClickCreateContractButton() - { - await _page.Locator("#createContractButton").ClickAsync(); - await Task.Delay(500); - } - - /// - /// Verify user is redirected to Contract Management page - /// - public async Task VerifyRedirectedToContractManagementPage() - { - await _page.WaitForURLAsync("**/contracts"); - var url = _page.Url; - url.ShouldEndWith("/contracts"); - } - - /// - /// Verify contract is created successfully - /// - public async Task VerifyContractCreatedSuccessfully() - { - // After creation, we should be on the contracts list page - await VerifyRedirectedToContractManagementPage(); - } - - /// - /// Click Add Product button - /// - public async Task ClickAddProductButton() - { - var button = _page.Locator("button:has-text('Add Product')").First; - await button.ClickAsync(); - await Task.Delay(300); - } - - /// - /// Verify Add Product modal is displayed - /// - public async Task VerifyAddProductModalIsDisplayed() - { - await _page.Locator("h3:has-text('Add New Product')").WaitForAsync(); - } - - /// - /// Enter text in product name field - /// - public async Task EnterProductName(string productName) - { - var input = _page.Locator("label:has-text('Product Name')").Locator("..").Locator("input"); - await input.FillAsync(productName); - } - - /// - /// Enter text in display text field - /// - public async Task EnterDisplayText(string displayText) - { - var input = _page.Locator("label:has-text('Display Text')").Locator("..").Locator("input"); - await input.FillAsync(displayText); - } - - /// - /// Enter value in the value field - /// - public async Task EnterValue(string value) - { - var input = _page.Locator("label:has-text('Value')").Locator("..").Locator("input"); - await input.FillAsync(value); - } - - /// - /// Check the Variable Value checkbox - /// - public async Task CheckVariableValueCheckbox() - { - var checkbox = _page.Locator("input[type='checkbox']"); - await checkbox.CheckAsync(); - } - - /// - /// Click Add Product button in modal - /// - public async Task ClickAddProductButtonInModal() - { - var button = _page.Locator(".bg-white.rounded-lg.p-6").Locator("button:has-text('Add Product')"); - await button.ClickAsync(); - await Task.Delay(500); - } - - /// - /// Verify product is added successfully - /// - public async Task VerifyProductAddedSuccessfully() - { - // Wait for modal to close - await _page.WaitForLoadStateAsync(LoadState.NetworkIdle); - var modalCount = await _page.Locator("h3:has-text('Add New Product')").CountAsync(); - modalCount.ShouldBe(0, "Add Product modal should be closed after successful addition"); - } - - /// - /// Verify Add Product modal is closed - /// - public async Task VerifyAddProductModalIsClosed() - { - var modalCount = await _page.Locator("h3:has-text('Add New Product')").CountAsync(); - modalCount.ShouldBe(0, "Add Product modal should be closed"); - } - - /// - /// Click Add Fee button for the first product - /// - public async Task ClickAddFeeButtonForFirstProduct() - { - var button = _page.Locator("button:has-text('Add Fee')").First; - await button.ClickAsync(); - await Task.Delay(300); - } - - /// - /// Verify Add Transaction Fee modal is displayed - /// - public async Task VerifyAddTransactionFeeModalIsDisplayed() - { - await _page.Locator("h3:has-text('Add Transaction Fee')").WaitForAsync(); - } - - /// - /// Enter text in fee description field - /// - public async Task EnterFeeDescription(string description) - { - var input = _page.Locator("label:has-text('Description')").Locator("..").Locator("input"); - await input.FillAsync(description); - } - - /// - /// Select calculation type from dropdown - /// - public async Task SelectCalculationType(string calculationType) - { - var select = _page.Locator("label:has-text('Calculation Type')").Locator("..").Locator("select"); - - // Map text to value with proper error handling - var value = calculationType.ToLower() switch - { - "fixed" => "0", - "percentage" => "1", - _ => throw new ArgumentException($"Unknown calculation type: {calculationType}. Expected 'Fixed' or 'Percentage'.") - }; - await select.SelectOptionAsync(new[] { value }); - } - - /// - /// Select fee type from dropdown - /// - public async Task SelectFeeType(string feeType) - { - var select = _page.Locator("label:has-text('Fee Type')").Locator("..").Locator("select"); - - // Map text to value with proper error handling - var value = feeType.ToLower() switch - { - "merchant" => "0", - "service provider" => "1", - _ => throw new ArgumentException($"Unknown fee type: {feeType}. Expected 'Merchant' or 'Service Provider'.") - }; - await select.SelectOptionAsync(new[] { value }); - } - - /// - /// Enter fee value - /// - public async Task EnterFeeValue(string value) - { - var input = _page.Locator("label:has-text('Fee Value')").Locator("..").Locator("input"); - await input.FillAsync(value); - } - - /// - /// Click Add Fee button in modal - /// - public async Task ClickAddFeeButtonInModal() - { - var button = _page.Locator(".bg-white.rounded-lg.p-6").Locator("button:has-text('Add Fee')"); - await button.ClickAsync(); - await Task.Delay(500); - } - - /// - /// Verify transaction fee is added successfully - /// - public async Task VerifyTransactionFeeAddedSuccessfully() - { - await _page.WaitForLoadStateAsync(LoadState.NetworkIdle); - var modalCount = await _page.Locator("h3:has-text('Add Transaction Fee')").CountAsync(); - modalCount.ShouldBe(0, "Add Transaction Fee modal should be closed after successful addition"); - } - - /// - /// Verify Add Transaction Fee modal is closed - /// - public async Task VerifyAddTransactionFeeModalIsClosed() - { - var modalCount = await _page.Locator("h3:has-text('Add Transaction Fee')").CountAsync(); - modalCount.ShouldBe(0, "Add Transaction Fee modal should be closed"); - } - - #endregion -} diff --git a/EstateManagementUI.IntegrationTests/Common/DashboardPageHelper.cs b/EstateManagementUI.IntegrationTests/Common/DashboardPageHelper.cs index 4e413d68..23d54b16 100644 --- a/EstateManagementUI.IntegrationTests/Common/DashboardPageHelper.cs +++ b/EstateManagementUI.IntegrationTests/Common/DashboardPageHelper.cs @@ -1,242 +1,309 @@ +using System.Runtime.CompilerServices; using Microsoft.Playwright; using Shouldly; +using System.Text.Json; +using System.Text.RegularExpressions; +using Shared.IntegrationTesting; namespace EstateManagementUI.IntegrationTests.Common; -/// -/// Helper class for interacting with the Dashboard page using Playwright -/// -public class DashboardPageHelper +public sealed class DashboardPageHelper { private readonly IPage _page; - private readonly string _baseUrl; + private readonly TestingContext TestingContext; - public DashboardPageHelper(IPage page, string baseUrl) - { + public DashboardPageHelper(IPage page, TestingContext testingContext) { _page = page; - _baseUrl = baseUrl; + this.TestingContext = testingContext; } - #region Navigation - - /// - /// Navigate to the home/dashboard page - /// - public async Task NavigateToDashboard() + public async Task NavigateToAppAddressAsync() { - await _page.GotoAsync(_baseUrl); + var baseUrl = ResolveBaseUrl(); + await _page.GotoAsync(baseUrl); await _page.WaitForLoadStateAsync(LoadState.NetworkIdle); } - #endregion + public async Task ClickSignInButtonAsync() + { + var signInButton = _page.Locator("#loginButton"); - #region Verification Methods + (await signInButton.IsVisibleAsync()).ShouldBeTrue(); + Console.WriteLine($"Sign in before click: {_page.Url}"); - /// - /// Verify the page title is "Dashboard" - /// - public async Task VerifyDashboardPageTitle() + await signInButton.ClickAsync(); + await _page.WaitForTimeoutAsync(2000); + Console.WriteLine($"Sign in after click: {_page.Url}"); + Console.WriteLine($"Sign in title after click: {await _page.TitleAsync()}"); + Console.WriteLine($"Sign in body after click: {await _page.Locator("body").InnerTextAsync()}"); + } + + public async Task AssertLoginScreenVisibleAsync() { - var title = await _page.TitleAsync(); - title.ShouldBe("Dashboard"); + await _page.WaitForLoadStateAsync(LoadState.DOMContentLoaded); + + (await WaitForAnyVisibleAsync( + "#Input_Username", + "input[name='Input.Username']", + "#Username", + "input[name='Username']", + "input[name='username']", + "input[type='email']", + "input[type='text']", + "input[autocomplete='username']")).ShouldBeTrue(); + + (await WaitForAnyVisibleAsync( + "#Input_Password", + "input[name='Input.Password']", + "#Password", + "input[name='Password']", + "input[name='password']", + "input[type='password']", + "input[autocomplete='current-password']")).ShouldBeTrue(); } - /// - /// Verify the Administrator welcome message is displayed - /// - public async Task VerifyAdministratorWelcomeMessage() + public async Task LoginAsync(string username, string password) { - var heading = await _page.Locator("h2:has-text('Welcome, Administrator')").TextContentAsync(); - heading.ShouldNotBeNull(); - heading.ShouldContain("Welcome, Administrator"); - - var description = await _page.Locator("p:has-text('administrative access')").TextContentAsync(); - description.ShouldNotBeNull(); - description.ShouldContain("administrative access to manage system permissions"); + await FillFirstVisibleAsync( + username, + "#Input_Username", + "input[name='Input.Username']", + "#Username", + "input[name='Username']", + "input[name='username']", + "input[type='email']", + "input[type='text']", + "input[autocomplete='username']"); + + await FillFirstVisibleAsync( + password, + "#Input_Password", + "input[name='Input.Password']", + "#Password", + "input[name='Password']", + "input[name='password']", + "input[type='password']", + "input[autocomplete='current-password']"); + + await ClickFirstVisibleAsync( + "button[type='submit']", + "input[type='submit']", + "button:has-text('Sign In')", + "button:has-text('Login')"); + + await _page.WaitForLoadStateAsync(LoadState.NetworkIdle); } - /// - /// Verify that KPI cards are visible on the dashboard - /// - public async Task VerifyKpiCardsAreVisible() + public async Task AssertDashboardShellVisibleAsync() { - await _page.Locator("text=Merchants with Sales (Last Hour)").WaitForAsync(); - await _page.Locator("text=Merchants with No Sales Today").WaitForAsync(); - await _page.Locator("text=Merchants with No Sales (7 Days)").WaitForAsync(); + (await _page.GetByRole(AriaRole.Heading, new() { Name = "Dashboard" }).IsVisibleAsync()).ShouldBeTrue(); + (await _page.GetByText("Welcome to Estate Management System").IsVisibleAsync()).ShouldBeTrue(); + (await _page.Locator("#dashboardLink").IsVisibleAsync()).ShouldBeTrue(); } - /// - /// Verify that KPI cards are NOT visible (Administrator role) - /// - public async Task VerifyKpiCardsAreNotVisible() + public async Task AssertHomePageVisibleAsync() { - var salesLastHourCount = await _page.Locator("text=Merchants with Sales (Last Hour)").CountAsync(); - salesLastHourCount.ShouldBe(0, "KPI cards should not be visible for Administrator role"); + (await _page.TitleAsync()).ShouldBe("Welcome - Estate Management"); + (await _page.Locator("#loginButton").IsVisibleAsync()).ShouldBeTrue(); } - /// - /// Verify Merchant KPI values match expected hardcoded test data - /// - public async Task VerifyMerchantKpiValues(int salesLastHour, int noSalesToday, int noSales7Days) + public async Task AssertDashboardWelcomeMessageVisibleAsync() { - // Wait for KPI cards to load - await _page.Locator("text=Merchants with Sales (Last Hour)").WaitForAsync(); + (await _page.GetByText("Welcome to Estate Management System").IsVisibleAsync()).ShouldBeTrue(); + } - // Verify Merchants with Sales in Last Hour - var salesLastHourCard = _page.Locator(".info-box").Filter(new LocatorFilterOptions - { - HasText = "Merchants with Sales (Last Hour)" - }); - var salesLastHourValue = await salesLastHourCard.Locator(".info-box-number").TextContentAsync(); - salesLastHourValue.ShouldNotBeNull(); - int.Parse(salesLastHourValue.Trim()).ShouldBe(salesLastHour); - - // Verify Merchants with No Sales Today - var noSalesTodayCard = _page.Locator(".info-box").Filter(new LocatorFilterOptions - { - HasText = "Merchants with No Sales Today" - }); - var noSalesTodayValue = await noSalesTodayCard.Locator(".info-box-number").TextContentAsync(); - noSalesTodayValue.ShouldNotBeNull(); - int.Parse(noSalesTodayValue.Trim()).ShouldBe(noSalesToday); - - // Verify Merchants with No Sales in Last 7 Days - var noSales7DaysCard = _page.Locator(".info-box").Filter(new LocatorFilterOptions - { - HasText = "Merchants with No Sales (7 Days)" - }); - var noSales7DaysValue = await noSales7DaysCard.Locator(".info-box-number").TextContentAsync(); - noSales7DaysValue.ShouldNotBeNull(); - int.Parse(noSales7DaysValue.Trim()).ShouldBe(noSales7Days); + public async Task AssertEstateDashboardVisibleAsync() + { + await AssertDashboardShellVisibleAsync(); + await AssertComparisonDateSelectorVisibleAsync(); + await AssertMerchantKpiSummaryCardsVisibleAsync(); + await AssertSalesComparisonCardsVisibleAsync(); + await AssertRecentMerchantsSectionVisibleAsync(); } - /// - /// Verify Today's Sales card is displayed - /// - public async Task VerifyTodaysSalesCardIsDisplayed() + public async Task AssertAdministratorDashboardVisibleAsync() { - await _page.Locator("h3:has-text(\"Today's Sales\")").WaitForAsync(); + await AssertDashboardShellVisibleAsync(); + (await _page.GetByRole(AriaRole.Heading, new() { Name = "Welcome, Administrator" }).IsVisibleAsync()).ShouldBeTrue(); } - /// - /// Verify Today's Sales values - /// - public async Task VerifyTodaysSalesValues(int todayCount, decimal todayValue) + public async Task AssertComparisonDateSelectorVisibleAsync() { - var salesCard = _page.Locator(".card").Filter(new LocatorFilterOptions - { - HasText = "Today's Sales" - }); - - // Wait for the card to be visible - await salesCard.WaitForAsync(); + var selector = _page.Locator("#comparisonDateSelector"); + var deadline = DateTime.UtcNow.AddSeconds(10); + + while (DateTime.UtcNow < deadline) + { + if (await selector.IsVisibleAsync()) + { + return; + } - // Verify today's sales count - var todayTransactions = await salesCard.Locator("p:has-text('transactions')").First.TextContentAsync(); - todayTransactions.ShouldNotBeNull(); - todayTransactions.ShouldContain($"{todayCount} transactions"); + await _page.WaitForTimeoutAsync(250); + } - // Verify today's sales value is displayed (currency format) - var todayValueText = await salesCard.Locator(".text-2xl.font-bold").First.TextContentAsync(); - todayValueText.ShouldNotBeNull(); - // Just verify value is present and formatted as currency - todayValueText.ShouldContain("$"); + (await _page.Locator("#comparisonDateSelector").IsVisibleAsync()).ShouldBeTrue(); } - /// - /// Verify Failed Sales card is displayed - /// - public async Task VerifyFailedSalesCardIsDisplayed() + public async Task AssertMerchantKpiSummaryCardsVisibleAsync() { - await _page.Locator("h3:has-text('Failed Sales (Low Credit)')").WaitForAsync(); + //await AssertInfoBoxVisibleAsync("Merchants with Sales (Last Hour)", "45"); + //await AssertInfoBoxVisibleAsync("Merchants with No Sales Today", "12"); + //await AssertInfoBoxVisibleAsync("Merchants with No Sales (7 Days)", "5"); + await AssertInfoBoxVisibleAsync("Merchants with Sales (Last Hour)", "0"); + await AssertInfoBoxVisibleAsync("Merchants with No Sales Today", "0"); + await AssertInfoBoxVisibleAsync("Merchants with No Sales (7 Days)", "0"); } - /// - /// Verify Failed Sales values - /// - public async Task VerifyFailedSalesValues(int todayCount) + public async Task AssertSalesComparisonCardsVisibleAsync() { - var failedSalesCard = _page.Locator(".card").Filter(new LocatorFilterOptions - { - HasText = "Failed Sales (Low Credit)" - }); - - // Wait for the card to be visible - await failedSalesCard.WaitForAsync(); + //await AssertCardVisibleAsync("Today's Sales", "523 transactions", new Regex(@"[£$]145,000\.00")); + //await AssertCardVisibleAsync("Failed Sales (Low Credit)", "15 transactions", new Regex(@"[£$]850\.00")); + await AssertCardVisibleAsync("Today's Sales", "0 transactions", new Regex(@"[£$¤]\s?0(?:,000)?\.00")); + await AssertCardVisibleAsync("Failed Sales (Low Credit)", "0 transactions", new Regex(@"[£$¤]\s?0(?:,000)?\.00")); + } + + public async Task AssertRecentMerchantsSectionVisibleAsync() + { + (await _page.GetByRole(AriaRole.Heading, new() { Name = "Recently Created Merchants" }).IsVisibleAsync()).ShouldBeTrue(); + } + + public async Task AssertMerchantKpiSummaryCardsNotVisibleAsync() + { + await AssertInfoBoxAbsentAsync("Merchants with Sales (Last Hour)"); + await AssertInfoBoxAbsentAsync("Merchants with No Sales Today"); + await AssertInfoBoxAbsentAsync("Merchants with No Sales (7 Days)"); + } - // Verify today's failed sales count - var todayTransactions = await failedSalesCard.Locator("p:has-text('transactions')").First.TextContentAsync(); - todayTransactions.ShouldNotBeNull(); - todayTransactions.ShouldContain($"{todayCount} transactions"); + public async Task AssertSalesComparisonCardsNotVisibleAsync() + { + await AssertCardAbsentAsync("Today's Sales"); + await AssertCardAbsentAsync("Failed Sales (Low Credit)"); } - /// - /// Verify comparison date selector is visible - /// - public async Task VerifyComparisonDateSelectorIsVisible() + public async Task AssertRecentMerchantsSectionNotVisibleAsync() { - await _page.Locator("label:has-text('Compare to:')").WaitForAsync(); - await _page.Locator("#comparisonDateSelector").WaitForAsync(); + (await _page.GetByRole(AriaRole.Heading, new() { Name = "Recently Created Merchants" }).CountAsync()).ShouldBe(0); } - /// - /// Verify comparison date selector is NOT visible (Administrator role) - /// - public async Task VerifyComparisonDateSelectorIsNotVisible() + public async Task AssertDashboardNavigationLinkVisibleAsync() { - var selectorCount = await _page.Locator("#comparisonDateSelector").CountAsync(); - selectorCount.ShouldBe(0, "Comparison date selector should not be visible for Administrator role"); + (await _page.Locator("#dashboardLink").IsVisibleAsync()).ShouldBeTrue(); } - /// - /// Verify Recently Created Merchants section is visible - /// - public async Task VerifyRecentlyCreatedMerchantsIsVisible() + private async Task AssertInfoBoxVisibleAsync(string label, string expectedValue) { - await _page.Locator("h3:has-text('Recently Created Merchants')").WaitForAsync(); + var card = _page.Locator(".info-box").Filter(new() { HasText = label }); + + (await card.IsVisibleAsync()).ShouldBeTrue(); + (await card.Locator(".info-box-number").InnerTextAsync()).ShouldBe(expectedValue); } - /// - /// Verify Recently Created Merchants section is NOT visible (Administrator role) - /// - public async Task VerifyRecentlyCreatedMerchantsIsNotVisible() + private async Task AssertInfoBoxAbsentAsync(string label) { - var merchantsCount = await _page.Locator("h3:has-text('Recently Created Merchants')").CountAsync(); - merchantsCount.ShouldBe(0, "Recently Created Merchants should not be visible for Administrator role"); + var card = _page.Locator(".info-box").Filter(new() { HasText = label }); + (await card.CountAsync()).ShouldBe(0); } - /// - /// Verify that at least one merchant is displayed in the Recently Created Merchants section - /// - public async Task VerifyRecentlyCreatedMerchantsHasData() + private async Task AssertCardVisibleAsync(string heading, params object[] expectedTexts) { - var merchantsCard = _page.Locator(".card").Filter(new LocatorFilterOptions - { - HasText = "Recently Created Merchants" + var card = _page.Locator("div.card").Filter(new() + { + Has = _page.GetByRole(AriaRole.Heading, new() { Name = heading }) }); - - await merchantsCard.WaitForAsync(); - - // Check that at least one merchant is displayed - var merchantItems = merchantsCard.Locator(".flex.items-center.justify-between"); - var count = await merchantItems.CountAsync(); - count.ShouldBeGreaterThan(0, "At least one merchant should be displayed"); + + (await card.IsVisibleAsync()).ShouldBeTrue(); + + foreach (var expectedText in expectedTexts) + { + var locator = expectedText is Regex regex + ? card.GetByText(regex).First + : card.GetByText(expectedText.ToString()!).First; + (await locator.IsVisibleAsync()).ShouldBeTrue(); + } } - #endregion + private async Task AssertCardAbsentAsync(string heading) + { + var card = _page.Locator("div.card").Filter(new() + { + Has = _page.GetByRole(AriaRole.Heading, new() { Name = heading }) + }); + (await card.CountAsync()).ShouldBe(0); + } + + private async Task WaitForAnyVisibleAsync(params string[] selectors) + { + var deadline = DateTime.UtcNow.AddSeconds(30); - #region Interaction Methods + while (DateTime.UtcNow < deadline) + { + if (await IsAnyVisibleAsync(selectors)) + { + return true; + } + + await _page.WaitForTimeoutAsync(250); + } + + return false; + } - /// - /// Select a comparison date from the dropdown - /// - public async Task SelectComparisonDate(string dateDescription) + private async Task IsAnyVisibleAsync(params string[] selectors) { - await _page.Locator("#comparisonDateSelector").SelectOptionAsync(new[] { dateDescription }); - // Wait for dashboard to reload - await Task.Delay(500); // Small delay for state update - await _page.WaitForLoadStateAsync(LoadState.NetworkIdle); + foreach (var selector in selectors) + { + var locator = _page.Locator(selector); + if (await locator.CountAsync() > 0 && await locator.First.IsVisibleAsync()) + { + return true; + } + } + + return false; + } + + private async Task FillFirstVisibleAsync(string value, params string[] selectors) + { + foreach (var selector in selectors) + { + var locator = _page.Locator(selector); + if (await locator.CountAsync() > 0) + { + var first = locator.First; + if (await first.IsVisibleAsync()) + { + await first.FillAsync(value); + return; + } + } + } + + throw new InvalidOperationException($"Could not find a visible input for selectors: {string.Join(", ", selectors)}"); } - #endregion + private async Task ClickFirstVisibleAsync(params string[] selectors) + { + foreach (var selector in selectors) + { + var locator = _page.Locator(selector); + if (await locator.CountAsync() > 0) + { + var first = locator.First; + if (await first.IsVisibleAsync()) + { + await first.ClickAsync(); + return; + } + } + } + + throw new InvalidOperationException($"Could not find a visible clickable element for selectors: {string.Join(", ", selectors)}"); + } + + private string ResolveBaseUrl() + { + var hostPort = this.TestingContext.DockerHelper.GetHostPort(ContainerType.EstateManagementUI); + return $"https://localhost:{hostPort}"; + } } diff --git a/EstateManagementUI.IntegrationTests/Common/DockerHelper.cs b/EstateManagementUI.IntegrationTests/Common/DockerHelper.cs new file mode 100644 index 00000000..3df9b31f --- /dev/null +++ b/EstateManagementUI.IntegrationTests/Common/DockerHelper.cs @@ -0,0 +1,691 @@ +using Ductus.FluentDocker.Common; +using Ductus.FluentDocker.Services; +using EventStore.Client; +using NLog; +using Reqnroll; +using SecurityService.Client; +using SecurityService.DataTransferObjects; +using Shared.IntegrationTesting; +using Shared.IntegrationTesting.TestContainers; +using Shared.Logger; +using Shared.Serialisation; +using Shouldly; +using System.Diagnostics; +using TransactionProcessor.Client; +using TransactionProcessor.IntegrationTesting.Helpers; +using ContainerBuilder = DotNet.Testcontainers.Builders.ContainerBuilder; +using ReqnrollTableHelper = Shared.IntegrationTesting.ReqnrollTableHelper; +using String = System.String; + +namespace EstateManagementUI.IntegrationTests.Common +{ + public class DockerHelper : global::Shared.IntegrationTesting.TestContainers.DockerHelper + { + #region Fields + + public ITransactionProcessorClient TransactionProcessorClient; + + public HttpClient HttpClient; + + public ISecurityServiceClient SecurityServiceClient; + + public EventStoreProjectionManagementClient ProjectionManagementClient; + + public HttpClient TestHostHttpClient; + + #endregion + + #region Constructors + + /// + /// Initializes a new instance of the class. + /// + /// The logger. + public DockerHelper() + { + this.TestingContext = new TestingContext(); + StringSerialiser.Initialise((IStringSerialiser)new SystemTextJsonSerializer(SystemTextJsonSerializer.GetDefaultJsonSerializerOptions())); + } + + String Serialise(Object arg) + { + return StringSerialiser.Serialise(arg, new SerialiserOptions(SerialiserPropertyFormat.SnakeCase)); + } + + Object Deserialise(String arg, Type type) + { + return StringSerialiser.DeserializeObject(arg, type, new SerialiserOptions(SerialiserPropertyFormat.SnakeCase)); + } + + #endregion + + #region Methods + + private readonly TestingContext TestingContext; + + public override void SetupContainerNames() + { + base.SetupContainerNames(); + this.SecurityServiceContainerName = $"identity-server{this.TestId:N}"; + this.EstateManagementUiContainerName = $"estateadministrationui{this.TestId:N}"; + Environment.SetEnvironmentVariable("SecurityServiceContainerName", this.SecurityServiceContainerName); + } + + private static void AddEntryToHostsFile(String ipaddress, + String hostname) + { + if (FdOs.IsWindows()) + { + var hostsPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.System), @"drivers\etc\hosts"); + using (StreamWriter w = File.AppendText(hostsPath)) + { + w.WriteLine($"{ipaddress} {hostname}"); + } + } + else if (FdOs.IsLinux()) + { + DockerHelper.ExecuteBashCommand($"echo {ipaddress} {hostname} | sudo tee -a /etc/hosts"); + } + } + + /// + /// Executes the bash command. + /// + /// The command. + /// + private static void ExecuteBashCommand(String command) + { + // according to: https://stackoverflow.com/a/15262019/637142 + // thans to this we will pass everything as one command + command = command.Replace("\"", "\"\""); + + var proc = new Process + { + StartInfo = new ProcessStartInfo + { + FileName = "/bin/bash", + Arguments = "-c \"" + command + "\"", + UseShellExecute = false, + RedirectStandardOutput = true, + CreateNoWindow = true + } + }; + Console.WriteLine(proc.StartInfo.Arguments); + + proc.Start(); + proc.WaitForExit(); + } + + public override async Task CreateSubscriptions() + { + List<(String streamName, String groupName, Int32 maxRetries)> subscriptions = new(); + subscriptions.AddRange(MessagingService.IntegrationTesting.Helpers.SubscriptionsHelper.GetSubscriptions()); + subscriptions.AddRange(TransactionProcessor.IntegrationTesting.Helpers.SubscriptionsHelper.GetSubscriptions()); + + // TODO: Add File Processor Subscriptions + + foreach ((String streamName, String groupName, Int32 maxRetries) subscription in subscriptions) + { + var x = subscription; + x.maxRetries = 2; + await this.CreatePersistentSubscription(x); + } + } + + protected override List GetRequiredProjections() + { + List requiredProjections = new List(); + + requiredProjections.Add("EstateAggregator.js"); + requiredProjections.Add("MerchantAggregator.js"); + requiredProjections.Add("MerchantBalanceCalculator.js"); + requiredProjections.Add("MerchantBalanceProjection.js"); + + return requiredProjections; + } + + //public override DotNet.Testcontainers.Builders.ContainerBuilder SetupTransactionProcessorContainer() + //{ + + // Dictionary variables = new (); + // variables.Add($"OperatorConfiguration:PataPawaPrePay:Url","http://{this.TestHostContainerName}:{DockerPorts.TestHostPort}/api/patapawaprepay"); + + // this.AdditionalVariables.Add(ContainerType.TransactionProcessor, variables); + + // return base.SetupTransactionProcessorContainer(); + //} + + /// + /// Starts the containers for scenario run. + /// + /// Name of the scenario. + public override async Task StartContainersForScenarioRun(String scenarioName, DockerServices dockerServices) + { + await base.StartContainersForScenarioRun(scenarioName, dockerServices); + Environment.SetEnvironmentVariable("SecurityServiceLocalPort", DockerPorts.SecurityServiceDockerPort.ToString()); + Environment.SetEnvironmentVariable("SecurityServicePort", this.SecurityServicePort.ToString()); + + //this.SetupEstateManagementUiContainer(); + + // Setup the base address resolvers + String TransactionProcessorBaseAddressResolver(String api) => $"http://127.0.0.1:{this.TransactionProcessorPort}"; + + HttpClientHandler clientHandler = new HttpClientHandler + { + ServerCertificateCustomValidationCallback = (message, + certificate2, + arg3, + arg4) => + { + return true; + } + + }; + HttpClient httpClient = new HttpClient(clientHandler); + this.TransactionProcessorClient = new TransactionProcessorClient(TransactionProcessorBaseAddressResolver, httpClient, this.Serialise, this.Deserialise); + Func securityServiceBaseAddressResolver = api => $"https://127.0.0.1:{this.SecurityServicePort}"; + this.SecurityServiceClient = new SecurityServiceClient(securityServiceBaseAddressResolver, httpClient, this.Serialise, this.Deserialise); + this.TestHostHttpClient = new HttpClient(clientHandler); + this.TestHostHttpClient.BaseAddress = new Uri($"http://127.0.0.1:{this.TestHostServicePort}"); + this.ProjectionManagementClient = new EventStoreProjectionManagementClient(ConfigureEventStoreSettings()); + } + + protected override ContainerBuilder SetupEstateManagementUiContainer() { + Trace("About to Start Estate Management UI Container"); + + Dictionary environmentVariables = this.GetCommonEnvironmentVariables(); + + environmentVariables.Remove("AppSettings:ClientId"); + environmentVariables.Remove("AppSettings:ClientSecret"); + + environmentVariables.Add("Authentication:Authority", $"https://{this.SecurityServiceContainerName}:0"); // The port is set to 0 to stop defaulting to 443 + //environmentVariables.Add("AppSettings:SecurityService", $"https://{this.SecurityServiceContainerName}:0"); // The port is set to 0 to stop defaulting to 443 + environmentVariables.Add("AppSettings:SecurityServiceLocalPort", $"{DockerPorts.SecurityServiceDockerPort}"); + environmentVariables.Add("AppSettings:SecurityServicePort", $"{this.SecurityServicePort}"); + environmentVariables.Add("AppSettings:HttpClientIgnoreCertificateErrors", $"true"); + //environmentVariables.Add($"AppSettings:PermissionsBypass=true"); + environmentVariables.Add("AppSettings:IsIntegrationTest", "true"); + environmentVariables.Add("ASPNETCORE_ENVIRONMENT", "Development"); + environmentVariables.Add("EstateManagementScope", "estateManagement"); + environmentVariables.Add("urls", "https://*:5004"); + environmentVariables.Add($"AppSettings:ClientId", "estateUIClient"); + environmentVariables.Add($"AppSettings:ClientSecret", "Secret1"); + environmentVariables.Add($"Authentication:ClientId", "estateUIClient"); + environmentVariables.Add($"Authentication:ClientSecret", "Secret1"); + environmentVariables.Add($"AppSettings:BackEndClientId", "serviceClient"); + environmentVariables.Add($"AppSettings:BackEndClientSecret", "Secret1"); + environmentVariables.Add($"DataReloadConfig:DefaultInSeconds", "1"); + environmentVariables.Add("ConnectionStrings:TransactionProcessorReadModel", this.SetConnectionString("TransactionProcessorReadModel", this.UseSecureSqlServerDatabase)); + environmentVariables.Add("AppSettings:EstateReportingApi", $"http://{this.EstateReportingContainerName}:{DockerPorts.EstateReportingDockerPort}"); + + (String imageName, Boolean useLatest) imageDetails = this.GetImageDetails(ContainerType.EstateManagementUI).Data; + + ContainerBuilder containerBuilder = new ContainerBuilder() + .WithName(this.EstateManagementUiContainerName) + .WithImage(imageDetails.imageName) + .WithEnvironment(environmentVariables) + .MountHostFolder(this.DockerPlatform, this.HostTraceFolder) + .WithPortBinding(DockerPorts.EstateManagementUIDockerPort, true); + + return containerBuilder; + } + + public override ContainerBuilder SetupEstateReportingContainer() { + Dictionary environmentVariables = new(); + environmentVariables.Add("ConnectionStrings:TransactionProcessorReadModel", this.SetConnectionString("TransactionProcessorReadModel", this.UseSecureSqlServerDatabase)); + this.AdditionalVariables.Add(ContainerType.EstateReporting, environmentVariables); + + return base.SetupEstateReportingContainer(); + } + + /*private async Task StartEstateManagementUiContainer(List networkServices, + Int32 securityServiceContainerPort, + Int32 securityServiceLocalPort) + { + TraceX("About to Start Estate Management UI Container"); + + Dictionary? environmentVariables = this.GetCommonEnvironmentVariables(); + environmentVariables.Add($"AppSettings:Authority","https://{this.SecurityServiceContainerName}:0"); // The port is set to 0 to stop defaulting to 443 + environmentVariables.Add($"AppSettings:SecurityServiceLocalPort", $"{securityServiceLocalPort}"); + environmentVariables.Add($"AppSettings:SecurityServicePort", $"{securityServiceContainerPort}"); + environmentVariables.Add("AppSettings:HttpClientIgnoreCertificateErrors","true"); + //environmentVariables.Add($"AppSettings:PermissionsBypass=true"); + environmentVariables.Add($"AppSettings:IsIntegrationTest","true"); + environmentVariables.Add($"ASPNETCORE_ENVIRONMENT","Development"); + environmentVariables.Add($"EstateManagementScope","estateManagement"); + environmentVariables.Add("urls","https://*:5004"); + environmentVariables.Add($"AppSettings:ClientId","estateUIClient"); + environmentVariables.Add($"AppSettings:ClientSecret","Secret1"); + environmentVariables.Add($"DataReloadConfig:DefaultInSeconds","1"); + environmentVariables.Add("AppSettings:HttpClientIgnoreCertificateErrors","true"); + environmentVariables.Add("ConnectionStrings:TransactionProcessorReadModel", this.SetConnectionString("TransactionProcessorReadModel", this.UseSecureSqlServerDatabase)); + + (String imageName, Boolean useLatest) imageDetails = this.GetImageDetails(ContainerType.EstateManangementUI).Data; + + TraceX("About to Built Estate Management UI Container"); + DotNet.Testcontainers.Builders.ContainerBuilder containerBuilder = new DotNet.Testcontainers.Builders.ContainerBuilder() + .WithName(this.EstateManagementUiContainerName) + .WithImage(imageDetails.imageName) + .WithEnvironment(environmentVariables) + //.UseNetwork(networkServices.ToArray()) + .MountHostFolder(this.DockerPlatform, this.HostTraceFolder); + + // Mount the folder to upload files + String uploadFolder = (this.DockerPlatform, isCi) switch + { + (DockerEnginePlatform.Windows, false) => "C:\\home\\txnproc\\reqnroll", + (DockerEnginePlatform.Windows, true) => "C:\\Users\\runneradmin\\txnproc\\reqnroll", + _ => "/home/txnproc/reqnroll" + }; + + if (this.DockerPlatform == DockerEnginePlatform.Windows && isCi) + { + Directory.CreateDirectory(uploadFolder); + } + + //String containerFolder = this.DockerPlatform == DockerEnginePlatform.Windows ? "C:\\home\\txnproc\\bulkfiles" : "/home/txnproc/bulkfiles"; + //fileProcessorContainer.Mount(uploadFolder, containerFolder, MountType.ReadWrite); + return containerBuilder; + + + IContainerService builtContainer = containerBuilder.Build(); + + try + { + + builtContainer.Start(); + builtContainer.WaitForPort("5004/tcp", 30000); + this.EstateManagementUiPort = builtContainer.ToHostExposedEndpoint($"5004/tcp").Port; + + await Task.Delay(5000); + + TraceX("Estate Management UI Started"); + + HttpClientHandler handler = new HttpClientHandler(); + handler.ServerCertificateCustomValidationCallback = + HttpClientHandler.DangerousAcceptAnyServerCertificateValidator; + // TODO: Refactor this code once it works... + using (HttpClient client = new HttpClient(handler)) + { + HttpRequestMessage createRolesRequest = new(HttpMethod.Post, + $"https://localhost:{this.EstateManagementUiPort}/api/Permissions/createRoles"); + + List roles = ["Administrator"]; + + createRolesRequest.Content = new StringContent(JsonConvert.SerializeObject(roles), Encoding.UTF8, + "application/json"); + + var response = await client.SendAsync(createRolesRequest, CancellationToken.None); + + if (response.IsSuccessStatusCode == false) + { + TraceX($"createRolesRequest failed [{response.StatusCode}]"); + } + HttpRequestMessage addUserToRoleRequest = new(HttpMethod.Post, + $"https://localhost:{this.EstateManagementUiPort}/api/Permissions/addUserToRole"); + List userRolesList = new List { + new AddUserToRole { UserName = "estateuser@testestate1.co.uk", RoleName = "Administrator" } + }; + + addUserToRoleRequest.Content = new StringContent(JsonConvert.SerializeObject(userRolesList), Encoding.UTF8, + "application/json"); + + response = await client.SendAsync(addUserToRoleRequest, CancellationToken.None); + if (response.IsSuccessStatusCode == false) + { + TraceX($"addUserToRoleRequest failed [{response.StatusCode}]"); + } + + + HttpRequestMessage getRolePermissionsRequest = new(HttpMethod.Get, + $"https://localhost:{this.EstateManagementUiPort}/api/Permissions/getRolePermissions?roleName=Administrator"); + + response = await client.SendAsync(getRolePermissionsRequest, CancellationToken.None); + + if (response.IsSuccessStatusCode == false) + { + TraceX($"getRolePermissionsRequest failed [{response.StatusCode}]"); + } + + var x = await response.Content.ReadAsStringAsync(CancellationToken.None); + + RolePermissionsObject rolePermissionsObject = JsonConvert.DeserializeObject(x); + + List<(int, string, int, string, bool)> Permissions = new(); + foreach (ApplicationSection applicationSection in rolePermissionsObject.ApplicationSections) + { + List<(Function, bool)> functionAccess = rolePermissionsObject.PermissionsList.Where(p => + p.ApplicationSection.ApplicationSectionId == applicationSection.ApplicationSectionId).Select(x => (x.Function, x.HasAccess)).ToList(); + + foreach ((Function, bool) function in functionAccess) + { + Permissions.Add((applicationSection.ApplicationSectionId, applicationSection.Name, function.Item1.FunctionId, function.Item1.Name, function.Item2)); + } + } + + List<(int, int, bool)> newPermissions = Permissions.Select(p => (p.Item1, p.Item3, true)).ToList(); + + HttpRequestMessage addRolePermissionsRequest = new(HttpMethod.Post, + $"https://localhost:{this.EstateManagementUiPort}/api/Permissions/addRolePermissions"); + + List rolePermissions = new() { + new RolePermissions { NewPermissions = newPermissions, RoleName = "Administrator" } + }; + + addRolePermissionsRequest.Content = new StringContent(JsonConvert.SerializeObject(rolePermissions), Encoding.UTF8, + "application/json"); + + response = await client.SendAsync(addRolePermissionsRequest, CancellationToken.None); + if (response.IsSuccessStatusCode == false) + { + TraceX($"addRolePermissionsRequest failed [{response.StatusCode}]"); + } + } + } + catch (Exception ex) + { + TraceX(ex.GetCombinedExceptionMessages()); + ConsoleStream logs = builtContainer.Logs(true, CancellationToken.None); + IList xx = logs.ReadToEnd(); + while (xx.Any()) + { + foreach (String s in xx) + { + TraceX($"Logs|{s}"); + } + xx = logs.ReadToEnd(); + } + } + + TraceX("About to attach networkServices"); + foreach (INetworkService networkService in networkServices) + { + networkService.Attach(builtContainer, false); + } + + //Trace("About to get port"); + //// Do a health check here + //var x = builtContainer.ToHostExposedEndpoint($"5004/tcp"); + //if (x == null){ + // Trace("x is null"); + //} + + + + + this.Containers.Add(((DockerServices)1024, builtContainer)); + //await Retry.For(async () => + //{ + // String healthCheck = + // await this.HealthCheckClient.PerformHealthCheck("http", "127.0.0.1", this.EstateManagementUiPort, CancellationToken.None); + + // var result = JsonConvert.DeserializeObject(healthCheck); + // result.Status.ShouldBe(HealthCheckStatus.Healthy.ToString(), $"Details {healthCheck}"); + //}); + + return builtContainer; + }*/ + + public override DotNet.Testcontainers.Builders.ContainerBuilder SetupSecurityServiceContainer() + { + this.TraceX("About to Start Security Container"); + + Retry.For(() => { + DockerHelper.AddEntryToHostsFile("127.0.0.1", SecurityServiceContainerName); + return Task.CompletedTask; + }); + + Retry.For(() => { + DockerHelper.AddEntryToHostsFile("localhost", SecurityServiceContainerName); + return Task.CompletedTask; + }); + + + Dictionary? environmentVariables = this.GetCommonEnvironmentVariables(); + environmentVariables.Add($"ServiceOptions:PublicOrigin",$"https://{this.SecurityServiceContainerName}:{DockerPorts.SecurityServiceDockerPort}"); + environmentVariables.Add($"ServiceOptions:IssuerUrl",$"https://{this.SecurityServiceContainerName}:{DockerPorts.SecurityServiceDockerPort}"); + environmentVariables.Add("ASPNETCORE_ENVIRONMENT","IntegrationTest"); + environmentVariables.Add($"urls",$"https://*:{DockerPorts.SecurityServiceDockerPort}"); + + environmentVariables.Add($"ServiceOptions:PasswordOptions:RequiredLength","6"); + environmentVariables.Add($"ServiceOptions:PasswordOptions:RequireDigit","false"); + environmentVariables.Add($"ServiceOptions:PasswordOptions:RequireUpperCase","false"); + environmentVariables.Add($"ServiceOptions:UserOptions:RequireUniqueEmail","false"); + environmentVariables.Add($"ServiceOptions:SignInOptions:RequireConfirmedEmail","false"); + + environmentVariables.Add("ConnectionStrings:PersistedGrantDbContext", this.SetConnectionString( $"PersistedGrantStore-{this.TestId}", this.UseSecureSqlServerDatabase)); + environmentVariables.Add("ConnectionStrings:ConfigurationDbContext", this.SetConnectionString( $"Configuration-{this.TestId}", this.UseSecureSqlServerDatabase)); + environmentVariables.Add("ConnectionStrings:AuthenticationDbContext", this.SetConnectionString( $"Authentication-{this.TestId}", this.UseSecureSqlServerDatabase)); + + environmentVariables.Add("Logging:LogLevel:Microsoft","Information"); + environmentVariables.Add("Logging:LogLevel:Default","Information"); + environmentVariables.Add("Logging:EventLog:LogLevel:Default","None"); + + (String imageName, Boolean useLatest) imageDetails = this.GetImageDetails(ContainerType.SecurityService).Data; + + ContainerBuilder? securityServiceContainer = new DotNet.Testcontainers.Builders.ContainerBuilder().WithName(this.SecurityServiceContainerName) + .WithEnvironment(environmentVariables) + .WithImage(imageDetails.imageName) + .WithPortBinding(DockerPorts.SecurityServiceDockerPort, true) + .MountHostFolder(this.DockerPlatform, this.HostTraceFolder); + + // Now build and return the container + return securityServiceContainer; + } + + /// + /// Stops the containers for scenario run. + /// + public override async Task StopContainersForScenarioRun(DockerServices sharedDockerServices) + { + await base.StopContainersForScenarioRun(sharedDockerServices); + } + + //private async Task CreatePermissionsRepository(String dbConnString, CancellationToken cancellationToken) + //{ + // var optionsBuilder = new DbContextOptionsBuilder(); + // optionsBuilder.UseSqlite(dbConnString); // Configure for your database provider + + // var serviceProvider = new ServiceCollection() + // .AddLogging(config => config.AddConsole()) // Add logging if needed + // .BuildServiceProvider(); + + // // Create the DbContextFactory instance + // var contextFactory = new DbContextFactory(serviceProvider, optionsBuilder.Options, new DbContextFactorySource()); + + // //var ctx = await contextFactory.CreateDbContextAsync(cancellationToken); + + // return new PermissionsRepository(contextFactory); + //} + + public void TraceX(String msg) + { + Trace(msg); + Console.WriteLine(msg); + } + + #endregion + } + + public class TestingContext + { + public EstateDetails GetEstateDetails(DataTableRow tableRow, Guid? testId = null) + { + String estateName = ReqnrollTableHelper.GetStringRowValue(tableRow, "EstateName").Replace("[id]", testId.Value.ToString("N")); + + EstateDetails estateDetails = this.Estates.SingleOrDefault(e => e.EstateName == estateName); + + estateDetails.ShouldNotBeNull(); + + return estateDetails; + } + + public List GetAllEstateIds() + { + return this.Estates.Select(e => e.EstateId).ToList(); + } + + public EstateDetails GetEstateDetails(String estateName) + { + EstateDetails estateDetails = this.Estates.SingleOrDefault(e => e.EstateName == estateName); + + estateDetails.ShouldNotBeNull(); + + return estateDetails; + } + + public EstateDetails GetEstateDetails(Guid estateId) + { + EstateDetails estateDetails = this.Estates.SingleOrDefault(e => e.EstateId == estateId); + + estateDetails.ShouldNotBeNull(); + + return estateDetails; + } + + public List Estates; + public void AddEstateDetails(Guid estateId, String estateName, String estateReference) + { + this.Estates.Add(EstateDetails.Create(estateId, estateName, estateReference)); + } + + public String AccessToken { get; set; } + + public DockerHelper DockerHelper { get; set; } + + public NlogLogger Logger { get; set; } + + public Dictionary Users; + public Dictionary Roles; + + public List Clients; + + public List ApiResources; + public List IdentityResources; + + public TokenResponse TokenResponse; + + public TestingContext() + { + this.Users = new Dictionary(); + this.Roles = new Dictionary(); + this.Clients = new List(); + this.ApiResources = new List(); + this.Estates = new List(); + this.IdentityResources = new List(); + } + + public ClientDetails GetClientDetails(String clientId) + { + ClientDetails clientDetails = this.Clients.SingleOrDefault(c => c.ClientId == clientId); + + clientDetails.ShouldNotBeNull(); + + return clientDetails; + } + + public void AddClientDetails(String clientId, + String clientSecret, + List grantTypes) + { + this.Clients.Add(ClientDetails.Create(clientId, clientSecret, grantTypes)); + } + } + + public class ClientDetails + { + public String ClientId { get; private set; } + public String ClientSecret { get; private set; } + public List GrantTypes { get; private set; } + + private ClientDetails(String clientId, + String clientSecret, + List grantTypes) + { + this.ClientId = clientId; + this.ClientSecret = clientSecret; + this.GrantTypes = grantTypes; + } + + public static ClientDetails Create(String clientId, + String clientSecret, + List grantTypes) + { + return new ClientDetails(clientId, clientSecret, grantTypes); + } + } + + [Binding] + public class Setup + { + public static (String usename, String password) SqlCredentials = ("sa", "thisisalongpassword123!"); + public static (String url, String username, String password) DockerCredentials = ("https://www.docker.com", "stuartferguson", "Sc0tland"); + + public static async Task GlobalSetup(DockerHelper dockerHelper) + { + ShouldlyConfiguration.DefaultTaskTimeout = TimeSpan.FromMinutes(5); + } + } + + [Binding] + [Scope(Tag = "base")] + public class GenericSteps + { + private readonly ScenarioContext ScenarioContext; + + private readonly TestingContext TestingContext; + + public GenericSteps(ScenarioContext scenarioContext, + TestingContext testingContext) + { + this.ScenarioContext = scenarioContext; + this.TestingContext = testingContext; + } + + [BeforeScenario(Order = 0)] + public async Task StartSystem() + { + // Initialise a logger + String scenarioName = this.ScenarioContext.ScenarioInfo.Title.Replace(" ", ""); + NlogLogger logger = new NlogLogger(); + logger.Initialise(LogManager.GetLogger(scenarioName), scenarioName); + LogManager.AddHiddenAssembly(typeof(NlogLogger).Assembly); + + DockerServices dockerServices = DockerServices.SqlServer | DockerServices.CallbackHandler | DockerServices.EventStore | + DockerServices.FileProcessor | DockerServices.MessagingService | DockerServices.SecurityService | + DockerServices.SqlServer | DockerServices.TransactionProcessor | + DockerServices.TransactionProcessorAcl | DockerServices.EstateManagementUI | + DockerServices.EstateReporting; + + this.TestingContext.DockerHelper = new DockerHelper(); + this.TestingContext.DockerHelper.Logger = logger; + this.TestingContext.Logger = logger; + this.TestingContext.DockerHelper.RequiredDockerServices = dockerServices; + this.TestingContext.Logger.LogInformation("About to Start Global Setup"); + + await Setup.GlobalSetup(this.TestingContext.DockerHelper); + + this.TestingContext.DockerHelper.DockerCredentials = Setup.DockerCredentials; + this.TestingContext.DockerHelper.SqlCredentials = Setup.SqlCredentials; + this.TestingContext.DockerHelper.SqlServerContainerName = "sharedsqlserver"; + + this.TestingContext.DockerHelper.SetImageDetails(ContainerType.EstateManagementUI, ("estatemanagementuiblazorserver", false)); + + this.TestingContext.Logger = logger; + this.TestingContext.Logger.LogInformation("About to Start Containers for Scenario Run"); + await this.TestingContext.DockerHelper.StartContainersForScenarioRun(scenarioName, dockerServices).ConfigureAwait(false); + this.TestingContext.Logger.LogInformation("Containers for Scenario Run Started"); + } + + [AfterScenario(Order = 1)] + public async Task StopSystem() + { + + DockerServices sharedDockerServices = DockerServices.None; + + this.TestingContext.Logger.LogInformation("About to Stop Containers for Scenario Run"); + await this.TestingContext.DockerHelper.StopContainersForScenarioRun(sharedDockerServices).ConfigureAwait(false); + this.TestingContext.Logger.LogInformation("Containers for Scenario Run Stopped"); + } + } +} diff --git a/EstateManagementUI.IntegrationTests/Common/EstateManagementPageHelper.cs b/EstateManagementUI.IntegrationTests/Common/EstateManagementPageHelper.cs deleted file mode 100644 index c7c61cdf..00000000 --- a/EstateManagementUI.IntegrationTests/Common/EstateManagementPageHelper.cs +++ /dev/null @@ -1,486 +0,0 @@ -using Microsoft.Playwright; -using Shouldly; - -namespace EstateManagementUI.IntegrationTests.Common; - -/// -/// Helper class for interacting with the Estate Management page using Playwright -/// -public class EstateManagementPageHelper -{ - private readonly IPage _page; - private readonly string _baseUrl; - - public EstateManagementPageHelper(IPage page, string baseUrl) - { - _page = page; - _baseUrl = baseUrl; - } - - #region Navigation - - /// - /// Navigate to the Estate Management page - /// - public async Task NavigateToEstateManagement() - { - await _page.GotoAsync($"{_baseUrl}/estate"); - await _page.WaitForLoadStateAsync(LoadState.NetworkIdle); - } - - /// - /// Navigate to home page to check menu visibility - /// - public async Task NavigateToHome() - { - await _page.GotoAsync(_baseUrl); - await _page.WaitForLoadStateAsync(LoadState.NetworkIdle); - } - - #endregion - - #region Menu Visibility Verification - - /// - /// Verify that Estate Management menu is not visible (Administrator role) - /// - public async Task VerifyEstateManagementMenuIsNotVisible() - { - // Wait a moment for the page to fully load - await Task.Delay(1000); - - var menuLinkCount = await _page.Locator("#estateDetailsLink").CountAsync(); - menuLinkCount.ShouldBe(0, "Estate Management menu should not be visible for Administrator role"); - } - - /// - /// Verify that Estate Management menu is visible - /// - public async Task VerifyEstateManagementMenuIsVisible() - { - await _page.Locator("#estateDetailsLink").WaitForAsync(); - var menuLinkCount = await _page.Locator("#estateDetailsLink").CountAsync(); - menuLinkCount.ShouldBeGreaterThan(0, "Estate Management menu should be visible"); - } - - #endregion - - #region Page Verification - - /// - /// Verify the Estate Management page is displayed - /// - public async Task VerifyEstateManagementPageIsDisplayed() - { - await _page.Locator("h1:has-text('Estate Management')").WaitForAsync(); - var heading = await _page.Locator("h1:has-text('Estate Management')").TextContentAsync(); - heading.ShouldNotBeNull(); - heading.ShouldContain("Estate Management"); - } - - /// - /// Verify the page title - /// - public async Task VerifyPageTitle(string expectedTitle) - { - var title = await _page.TitleAsync(); - title.ShouldBe(expectedTitle); - } - - #endregion - - #region Estate Details Verification - - /// - /// Verify estate name is displayed correctly - /// - public async Task VerifyEstateName(string expectedName) - { - var estateNameInput = _page.Locator("#Estate_Name"); - await estateNameInput.WaitForAsync(); - var actualName = await estateNameInput.InputValueAsync(); - actualName.ShouldBe(expectedName); - } - - /// - /// Verify estate reference is displayed correctly - /// - public async Task VerifyEstateReference(string expectedReference) - { - var estateRefInput = _page.Locator("#Estate_Reference"); - await estateRefInput.WaitForAsync(); - var actualReference = await estateRefInput.InputValueAsync(); - actualReference.ShouldBe(expectedReference); - } - - #endregion - - #region Statistics Verification - - /// - /// Verify Total Merchants count - /// - public async Task VerifyTotalMerchantsCount(int expectedCount) - { - var merchantsCard = _page.Locator(".bg-gray-50.rounded-lg.p-6").Filter(new LocatorFilterOptions - { - HasText = "Total Merchants" - }); - - await merchantsCard.WaitForAsync(); - - var countText = await merchantsCard.Locator(".text-3xl.font-bold").TextContentAsync(); - countText.ShouldNotBeNull(); - int.Parse(countText.Trim()).ShouldBe(expectedCount); - } - - /// - /// Verify Total Operators count - /// - public async Task VerifyTotalOperatorsCount(int expectedCount) - { - var operatorsCard = _page.Locator(".bg-gray-50.rounded-lg.p-6").Filter(new LocatorFilterOptions - { - HasText = "Total Operators" - }); - - await operatorsCard.WaitForAsync(); - - var countText = await operatorsCard.Locator(".text-3xl.font-bold").TextContentAsync(); - countText.ShouldNotBeNull(); - int.Parse(countText.Trim()).ShouldBe(expectedCount); - } - - /// - /// Verify Total Contracts count - /// - public async Task VerifyTotalContractsCount(int expectedCount) - { - var contractsCard = _page.Locator(".bg-gray-50.rounded-lg.p-6").Filter(new LocatorFilterOptions - { - HasText = "Total Contracts" - }); - - await contractsCard.WaitForAsync(); - - var countText = await contractsCard.Locator(".text-3xl.font-bold").TextContentAsync(); - countText.ShouldNotBeNull(); - int.Parse(countText.Trim()).ShouldBe(expectedCount); - } - - /// - /// Verify Total Users count - /// - public async Task VerifyTotalUsersCount(int expectedCount) - { - var usersCard = _page.Locator(".bg-gray-50.rounded-lg.p-6").Filter(new LocatorFilterOptions - { - HasText = "Total Users" - }); - - await usersCard.WaitForAsync(); - - var countText = await usersCard.Locator(".text-3xl.font-bold").TextContentAsync(); - countText.ShouldNotBeNull(); - int.Parse(countText.Trim()).ShouldBe(expectedCount); - } - - #endregion - - #region Recent Merchants Section - - /// - /// Verify Recent Merchants section is displayed - /// - public async Task VerifyRecentMerchantsSection() - { - await _page.Locator("h2:has-text('Recent Merchants')").WaitForAsync(); - } - - /// - /// Verify at least a certain number of merchants are shown - /// - public async Task VerifyRecentMerchantsCount(int minCount) - { - var merchantsSection = _page.Locator(".bg-gray-50.rounded-lg.p-6").Filter(new LocatorFilterOptions - { - HasText = "Recent Merchants" - }); - - await merchantsSection.WaitForAsync(); - - var merchantItems = merchantsSection.Locator(".flex.items-center.justify-between.p-3.bg-white.rounded-lg"); - var count = await merchantItems.CountAsync(); - count.ShouldBeGreaterThanOrEqualTo(minCount, $"At least {minCount} merchant(s) should be displayed"); - } - - /// - /// Verify a specific merchant is visible by name and reference - /// - public async Task VerifyMerchantIsVisible(string merchantName, string merchantReference) - { - var merchantsSection = _page.Locator(".bg-gray-50.rounded-lg.p-6").Filter(new LocatorFilterOptions - { - HasText = "Recent Merchants" - }); - - await merchantsSection.WaitForAsync(); - - // Find merchant by name - var merchantNameLocator = merchantsSection.Locator($"p.font-medium:has-text('{merchantName}')"); - await merchantNameLocator.WaitForAsync(); - - // Verify reference is present in the same container - var merchantItem = merchantNameLocator.Locator("../.."); - var referenceText = await merchantItem.Locator($"p.text-sm:has-text('{merchantReference}')").TextContentAsync(); - referenceText.ShouldNotBeNull(); - referenceText.ShouldContain(merchantReference); - } - - #endregion - - #region Contracts Section - - /// - /// Verify Contracts section is displayed - /// - public async Task VerifyContractsSection() - { - await _page.Locator("h2:has-text('Contracts')").WaitForAsync(); - } - - /// - /// Verify at least a certain number of contracts are shown - /// - public async Task VerifyContractsCount(int minCount) - { - var contractsSection = _page.Locator(".bg-gray-50.rounded-lg.p-6").Filter(new LocatorFilterOptions - { - HasText = "Contracts" - }); - - await contractsSection.WaitForAsync(); - - var contractItems = contractsSection.Locator(".flex.items-center.justify-between.p-3.bg-white.rounded-lg"); - var count = await contractItems.CountAsync(); - count.ShouldBeGreaterThanOrEqualTo(minCount, $"At least {minCount} contract(s) should be displayed"); - } - - /// - /// Verify a specific contract is visible by description and operator - /// - public async Task VerifyContractIsVisible(string contractDescription, string operatorName) - { - var contractsSection = _page.Locator(".bg-gray-50.rounded-lg.p-6").Filter(new LocatorFilterOptions - { - HasText = "Contracts" - }); - - await contractsSection.WaitForAsync(); - - // Find contract by description - var contractDescLocator = contractsSection.Locator($"p.font-medium:has-text('{contractDescription}')"); - await contractDescLocator.WaitForAsync(); - - // Verify operator name is present in the same container - var contractItem = contractDescLocator.Locator("../.."); - var operatorText = await contractItem.Locator($"p.text-sm:has-text('{operatorName}')").TextContentAsync(); - operatorText.ShouldNotBeNull(); - operatorText.ShouldContain(operatorName); - } - - #endregion - - #region Tab Navigation - - /// - /// Click on a specific tab - /// - public async Task ClickTab(string tabName) - { - var tabButton = _page.Locator($"button:has-text('{tabName.Substring(0, 1).ToUpper()}{tabName.Substring(1)}')"); - await tabButton.WaitForAsync(); - await tabButton.ClickAsync(); - - // Wait for tab content to load - await Task.Delay(500); - await _page.WaitForLoadStateAsync(LoadState.NetworkIdle); - } - - /// - /// Verify operators tab content is displayed - /// - public async Task VerifyOperatorsTabContent() - { - await _page.Locator("h3:has-text('Assigned Operators')").WaitForAsync(); - } - - #endregion - - #region Operators Tab - - /// - /// Verify Assigned Operators section is visible - /// - public async Task VerifyAssignedOperatorsSection() - { - await _page.Locator("h3:has-text('Assigned Operators')").WaitForAsync(); - } - - /// - /// Verify the number of assigned operators - /// - public async Task VerifyAssignedOperatorsCount(int minCount) - { - await _page.Locator("h3:has-text('Assigned Operators')").WaitForAsync(); - - var operatorItems = _page.Locator(".flex.items-center.justify-between.p-3.bg-gray-50.rounded-lg"); - var count = await operatorItems.CountAsync(); - count.ShouldBeGreaterThanOrEqualTo(minCount, $"At least {minCount} operator(s) should be assigned"); - } - - /// - /// Verify a specific operator is listed - /// - public async Task VerifyOperatorIsListed(string operatorName) - { - var operatorLocator = _page.Locator($".flex.items-center.justify-between.p-3.bg-gray-50.rounded-lg span.font-medium:has-text('{operatorName}')"); - await operatorLocator.WaitForAsync(); - - var text = await operatorLocator.TextContentAsync(); - text.ShouldNotBeNull(); - text.ShouldContain(operatorName); - } - - /// - /// Verify Add Operator button is visible - /// - public async Task VerifyAddOperatorButtonIsVisible() - { - await _page.Locator("#addOperatorButton").WaitForAsync(); - var isVisible = await _page.Locator("#addOperatorButton").IsVisibleAsync(); - isVisible.ShouldBeTrue("Add Operator button should be visible for Estate role"); - } - - /// - /// Verify Add Operator button is not visible - /// - public async Task VerifyAddOperatorButtonIsNotVisible() - { - // Wait a moment for the page to fully load - await Task.Delay(1000); - - var buttonCount = await _page.Locator("#addOperatorButton").CountAsync(); - buttonCount.ShouldBe(0, "Add Operator button should not be visible for Viewer role"); - } - - #endregion - - #region Add/Remove Operator Actions - - /// - /// Remove an operator from the estate - /// - public async Task RemoveOperator(string operatorName) - { - // Find the operator item by name - var operatorItem = _page.Locator(".flex.items-center.justify-between.p-3.bg-gray-50.rounded-lg") - .Filter(new LocatorFilterOptions { HasText = operatorName }); - - await operatorItem.WaitForAsync(); - - // Click the Remove button - var removeButton = operatorItem.Locator("button:has-text('Remove')"); - await removeButton.ClickAsync(); - - // Wait for the action to complete - await Task.Delay(500); - await _page.WaitForLoadStateAsync(LoadState.NetworkIdle); - } - - /// - /// Click the Add Operator button - /// - public async Task ClickAddOperatorButton() - { - await _page.Locator("#addOperatorButton").ClickAsync(); - - // Wait for the form to appear - await Task.Delay(500); - } - - /// - /// Select an operator from the dropdown - /// - public async Task SelectOperatorFromDropdown(string operatorName) - { - var dropdown = _page.Locator("select.input.flex-1"); - await dropdown.WaitForAsync(); - await dropdown.SelectOptionAsync(new[] { operatorName }); - - // Wait for selection to register - await Task.Delay(300); - } - - /// - /// Click the Add button in the operator form - /// - public async Task ClickAddButton() - { - var addButton = _page.Locator("button.btn.btn-primary:has-text('Add')"); - await addButton.ClickAsync(); - - // Wait for the action to complete - await Task.Delay(500); - await _page.WaitForLoadStateAsync(LoadState.NetworkIdle); - } - - /// - /// Verify success message is displayed - /// - public async Task VerifySuccessMessageIsDisplayed() - { - var successMessage = _page.Locator(".bg-green-50.border.border-green-200.text-green-800"); - await successMessage.WaitForAsync(); - - var isVisible = await successMessage.IsVisibleAsync(); - isVisible.ShouldBeTrue("Success message should be displayed"); - } - - /// - /// Verify success message contains expected text - /// - public async Task VerifySuccessMessageContains(string expectedMessage) - { - var successMessage = _page.Locator(".bg-green-50.border.border-green-200.text-green-800"); - await successMessage.WaitForAsync(); - - var messageText = await successMessage.TextContentAsync(); - messageText.ShouldNotBeNull(); - messageText.ShouldContain(expectedMessage); - } - - /// - /// Verify an operator is NOT listed (after removal) - /// - public async Task VerifyOperatorIsNotListed(string operatorName) - { - // Wait a moment for removal to complete - await Task.Delay(500); - - var operatorCount = await _page.Locator($".flex.items-center.justify-between.p-3.bg-gray-50.rounded-lg span.font-medium:has-text('{operatorName}')").CountAsync(); - operatorCount.ShouldBe(0, $"Operator '{operatorName}' should not be listed after removal"); - } - - /// - /// Verify operator selection form is displayed - /// - public async Task VerifyOperatorSelectionFormIsDisplayed() - { - await _page.Locator("select.input.flex-1").WaitForAsync(); - var isVisible = await _page.Locator("select.input.flex-1").IsVisibleAsync(); - isVisible.ShouldBeTrue("Operator selection form should be displayed"); - } - - #endregion -} diff --git a/EstateManagementUI.IntegrationTests/Common/MerchantManagementPageHelper.cs b/EstateManagementUI.IntegrationTests/Common/MerchantManagementPageHelper.cs deleted file mode 100644 index 35233d5f..00000000 --- a/EstateManagementUI.IntegrationTests/Common/MerchantManagementPageHelper.cs +++ /dev/null @@ -1,1114 +0,0 @@ -using Microsoft.Playwright; -using Shouldly; - -namespace EstateManagementUI.IntegrationTests.Common; - -/// -/// Helper class for interacting with the Merchant Management pages using Playwright -/// -public class MerchantManagementPageHelper -{ - private readonly IPage _page; - private readonly string _baseUrl; - - public MerchantManagementPageHelper(IPage page, string baseUrl) - { - _page = page; - _baseUrl = baseUrl; - } - - #region Navigation - - /// - /// Navigate to the Merchant Management page (index) - /// - public async Task NavigateToMerchantManagement() - { - await _page.GotoAsync($"{_baseUrl}/merchants"); - await _page.WaitForLoadStateAsync(LoadState.NetworkIdle); - } - - /// - /// Navigate to home page to check menu visibility - /// - public async Task NavigateToHome() - { - await _page.GotoAsync(_baseUrl); - await _page.WaitForLoadStateAsync(LoadState.NetworkIdle); - } - - #endregion - - #region Menu Visibility Verification - - /// - /// Verify that Merchant Management menu is not visible (Administrator role) - /// - public async Task VerifyMerchantManagementMenuIsNotVisible() - { - // Wait a moment for the page to fully load - await Task.Delay(1000); - - var menuLinkCount = await _page.Locator("text=Merchant Management").CountAsync(); - menuLinkCount.ShouldBe(0, "Merchant Management menu should not be visible for Administrator role"); - } - - /// - /// Verify that Merchant Management menu is visible - /// - public async Task VerifyMerchantManagementMenuIsVisible() - { - await _page.Locator("text=Merchant Management").WaitForAsync(); - var menuLinkCount = await _page.Locator("text=Merchant Management").CountAsync(); - menuLinkCount.ShouldBeGreaterThan(0, "Merchant Management menu should be visible"); - } - - #endregion - - #region Page Verification - - /// - /// Verify the Merchant Management page is displayed - /// - public async Task VerifyMerchantManagementPageIsDisplayed() - { - await _page.Locator("h1:has-text('Merchant Management')").WaitForAsync(); - var heading = await _page.Locator("h1:has-text('Merchant Management')").TextContentAsync(); - heading.ShouldNotBeNull(); - heading.ShouldContain("Merchant Management"); - } - - /// - /// Verify the page title - /// - public async Task VerifyPageTitle(string expectedTitle) - { - var title = await _page.TitleAsync(); - title.ShouldBe(expectedTitle); - } - - /// - /// Verify the View Merchant page is displayed - /// - public async Task VerifyViewMerchantPageIsDisplayed() - { - await _page.Locator("h1:has-text('View Merchant')").WaitForAsync(); - var heading = await _page.Locator("h1").TextContentAsync(); - heading.ShouldNotBeNull(); - heading.ShouldContain("View Merchant"); - } - - /// - /// Verify the Create New Merchant page is displayed - /// - public async Task VerifyCreateNewMerchantPageIsDisplayed() - { - await _page.Locator("h1:has-text('Create New Merchant')").WaitForAsync(); - var heading = await _page.Locator("h1:has-text('Create New Merchant')").TextContentAsync(); - heading.ShouldNotBeNull(); - heading.ShouldContain("Create New Merchant"); - } - - /// - /// Verify the Edit Merchant page is displayed - /// - public async Task VerifyEditMerchantPageIsDisplayed() - { - await _page.Locator("h1:has-text('Edit Merchant')").WaitForAsync(); - var heading = await _page.Locator("h1").TextContentAsync(); - heading.ShouldNotBeNull(); - heading.ShouldContain("Edit Merchant"); - } - - /// - /// Verify the Make Deposit page is displayed - /// - public async Task VerifyMakeDepositPageIsDisplayed() - { - await _page.Locator("h1:has-text('Make Merchant Deposit')").WaitForAsync(); - var heading = await _page.Locator("h1:has-text('Make Merchant Deposit')").TextContentAsync(); - heading.ShouldNotBeNull(); - heading.ShouldContain("Make Merchant Deposit"); - } - - #endregion - - #region Merchant List Verification - - /// - /// Verify the number of merchants in the list - /// - public async Task VerifyMerchantListCount(int expectedCount) - { - await _page.Locator("#merchantList tbody tr").First.WaitForAsync(); - var merchantRows = await _page.Locator("#merchantList tbody tr").CountAsync(); - merchantRows.ShouldBe(expectedCount, $"Expected {expectedCount} merchants in the list"); - } - - /// - /// Verify a specific merchant is listed with name and reference - /// - public async Task VerifyMerchantIsListed(string merchantName, string merchantReference) - { - // Wait for the merchant list to load - await _page.Locator("#merchantList").WaitForAsync(); - - // Find the row containing the merchant name - var merchantRow = _page.Locator($"#merchantList tbody tr:has-text('{merchantName}')"); - await merchantRow.WaitForAsync(); - - var rowCount = await merchantRow.CountAsync(); - rowCount.ShouldBeGreaterThan(0, $"Merchant '{merchantName}' should be visible in the list"); - - // Verify the reference is in the same row - var referenceCell = merchantRow.Locator($"text={merchantReference}"); - var refCount = await referenceCell.CountAsync(); - refCount.ShouldBeGreaterThan(0, $"Merchant reference '{merchantReference}' should be visible for '{merchantName}'"); - } - - /// - /// Verify merchant balance information - /// - public async Task VerifyMerchantBalance(string merchantName, string expectedBalance) - { - var merchantRow = _page.Locator($"#merchantList tbody tr:has-text('{merchantName}')"); - await merchantRow.WaitForAsync(); - - var balanceCell = merchantRow.Locator($"text={expectedBalance}"); - var balanceCount = await balanceCell.CountAsync(); - balanceCount.ShouldBeGreaterThan(0, $"Merchant '{merchantName}' should show balance '{expectedBalance}'"); - } - - /// - /// Verify merchant available balance information - /// - public async Task VerifyMerchantAvailableBalance(string merchantName, string expectedAvailableBalance) - { - var merchantRow = _page.Locator($"#merchantList tbody tr:has-text('{merchantName}')"); - await merchantRow.WaitForAsync(); - - var availableBalanceCell = merchantRow.Locator($"text={expectedAvailableBalance}"); - var availableBalanceCount = await availableBalanceCell.CountAsync(); - availableBalanceCount.ShouldBeGreaterThan(0, $"Merchant '{merchantName}' should show available balance '{expectedAvailableBalance}'"); - } - - /// - /// Verify merchant settlement schedule - /// - public async Task VerifyMerchantSettlementSchedule(string merchantName, string expectedSchedule) - { - var merchantRow = _page.Locator($"#merchantList tbody tr:has-text('{merchantName}')"); - await merchantRow.WaitForAsync(); - - var scheduleCell = merchantRow.Locator($"text={expectedSchedule}"); - var scheduleCount = await scheduleCell.CountAsync(); - scheduleCount.ShouldBeGreaterThan(0, $"Merchant '{merchantName}' should show settlement schedule '{expectedSchedule}'"); - } - - #endregion - - #region Button Visibility - - /// - /// Verify the Add New Merchant button is visible - /// - public async Task VerifyAddNewMerchantButtonIsVisible() - { - var buttonCount = await _page.Locator("#newMerchantButton").CountAsync(); - buttonCount.ShouldBeGreaterThan(0, "Add New Merchant button should be visible for Estate role"); - } - - /// - /// Verify the Add New Merchant button is not visible - /// - public async Task VerifyAddNewMerchantButtonIsNotVisible() - { - await Task.Delay(500); // Wait a moment for page to render - var buttonCount = await _page.Locator("#newMerchantButton").CountAsync(); - buttonCount.ShouldBe(0, "Add New Merchant button should not be visible for Viewer role"); - } - - /// - /// Verify the Edit button is visible for a specific merchant - /// - public async Task VerifyEditButtonIsVisibleForMerchant(string merchantName) - { - var merchantRow = _page.Locator($"#merchantList tbody tr:has-text('{merchantName}')"); - await merchantRow.WaitForAsync(); - - var editButton = merchantRow.Locator("#editMerchantLink"); - var editButtonCount = await editButton.CountAsync(); - editButtonCount.ShouldBeGreaterThan(0, $"Edit button should be visible for merchant '{merchantName}'"); - } - - /// - /// Verify the Edit button is not visible for a specific merchant - /// - public async Task VerifyEditButtonIsNotVisibleForMerchant(string merchantName) - { - var merchantRow = _page.Locator($"#merchantList tbody tr:has-text('{merchantName}')"); - await merchantRow.WaitForAsync(); - - await Task.Delay(500); // Wait a moment for page to render - var editButton = merchantRow.Locator("#editMerchantLink"); - var editButtonCount = await editButton.CountAsync(); - editButtonCount.ShouldBe(0, $"Edit button should not be visible for merchant '{merchantName}' for Viewer role"); - } - - /// - /// Verify the Make Deposit button is visible for a specific merchant - /// - public async Task VerifyMakeDepositButtonIsVisibleForMerchant(string merchantName) - { - var merchantRow = _page.Locator($"#merchantList tbody tr:has-text('{merchantName}')"); - await merchantRow.WaitForAsync(); - - var depositButton = merchantRow.Locator("#makeDepositLink"); - var depositButtonCount = await depositButton.CountAsync(); - depositButtonCount.ShouldBeGreaterThan(0, $"Make Deposit button should be visible for merchant '{merchantName}'"); - } - - /// - /// Verify the Make Deposit button is not visible for a specific merchant - /// - public async Task VerifyMakeDepositButtonIsNotVisibleForMerchant(string merchantName) - { - var merchantRow = _page.Locator($"#merchantList tbody tr:has-text('{merchantName}')"); - await merchantRow.WaitForAsync(); - - await Task.Delay(500); // Wait a moment for page to render - var depositButton = merchantRow.Locator("#makeDepositLink"); - var depositButtonCount = await depositButton.CountAsync(); - depositButtonCount.ShouldBe(0, $"Make Deposit button should not be visible for merchant '{merchantName}' for Viewer role"); - } - - #endregion - - #region Merchant Detail Verification - - /// - /// Verify merchant name in the detail view - /// - public async Task VerifyMerchantName(string expectedName) - { - var nameElement = _page.Locator("p.font-medium.text-gray-900").Filter(new LocatorFilterOptions - { - HasText = expectedName - }); - await nameElement.WaitForAsync(); - var nameText = await nameElement.TextContentAsync(); - nameText.ShouldNotBeNull(); - nameText.ShouldBe(expectedName); - } - - /// - /// Verify merchant reference in the detail view - /// - public async Task VerifyMerchantReference(string expectedReference) - { - var referenceElement = _page.Locator("p.font-mono").Filter(new LocatorFilterOptions - { - HasText = expectedReference - }); - await referenceElement.WaitForAsync(); - var referenceText = await referenceElement.TextContentAsync(); - referenceText.ShouldNotBeNull(); - referenceText.ShouldBe(expectedReference); - } - - /// - /// Verify merchant balance in the detail view - /// - public async Task VerifyMerchantBalanceDetail(string expectedBalance) - { - // Wait for the balance to load - await _page.Locator("text=Balance").WaitForAsync(); - - var balanceElement = _page.Locator(".text-green-600").Filter(new LocatorFilterOptions - { - HasText = expectedBalance - }); - var balanceCount = await balanceElement.CountAsync(); - balanceCount.ShouldBeGreaterThan(0, $"Merchant should show balance '{expectedBalance}'"); - } - - /// - /// Verify merchant available balance in the detail view - /// - public async Task VerifyMerchantAvailableBalanceDetail(string expectedAvailableBalance) - { - // Wait for the available balance to load - await _page.Locator("text=Available Balance").WaitForAsync(); - - var availableBalanceElement = _page.Locator(".text-blue-600").Filter(new LocatorFilterOptions - { - HasText = expectedAvailableBalance - }); - var availableBalanceCount = await availableBalanceElement.CountAsync(); - availableBalanceCount.ShouldBeGreaterThan(0, $"Merchant should show available balance '{expectedAvailableBalance}'"); - } - - /// - /// Verify merchant settlement schedule in the detail view - /// - public async Task VerifyMerchantSettlementScheduleDetail(string expectedSchedule) - { - await _page.Locator("text=Settlement Schedule").WaitForAsync(); - - var scheduleElement = _page.Locator($"text={expectedSchedule}"); - var scheduleCount = await scheduleElement.CountAsync(); - scheduleCount.ShouldBeGreaterThan(0, $"Merchant should show settlement schedule '{expectedSchedule}'"); - } - - #endregion - - #region Tab Navigation and Verification - - /// - /// Click on a specific tab (address, contact, operators, contracts, devices, etc.) - /// - public async Task ClickTab(string tabName) - { - await _page.Locator($"button:has-text('{tabName}')").ClickAsync(); - await Task.Delay(500); // Wait for tab content to load - } - - /// - /// Verify the address tab content is displayed - /// - public async Task VerifyAddressTabContent() - { - await _page.Locator("text=Address Line 1").WaitForAsync(); - var addressHeading = await _page.Locator("text=Address Line 1").CountAsync(); - addressHeading.ShouldBeGreaterThan(0, "Address tab content should be displayed"); - } - - /// - /// Verify the contact tab content is displayed - /// - public async Task VerifyContactTabContent() - { - await _page.Locator("text=Contact Name").WaitForAsync(); - var contactHeading = await _page.Locator("text=Contact Name").CountAsync(); - contactHeading.ShouldBeGreaterThan(0, "Contact tab content should be displayed"); - } - - /// - /// Verify the operators tab content is displayed - /// - public async Task VerifyOperatorsTabContent() - { - await _page.Locator("text=Assigned Operators").WaitForAsync(); - var operatorsSection = await _page.Locator("text=Assigned Operators").CountAsync(); - operatorsSection.ShouldBeGreaterThan(0, "Operators tab content should be displayed"); - } - - /// - /// Verify the Assigned Operators section is visible - /// - public async Task VerifyAssignedOperatorsSection() - { - await _page.Locator("text=Assigned Operators").WaitForAsync(); - } - - /// - /// Verify the contracts tab content is displayed - /// - public async Task VerifyContractsTabContent() - { - await _page.Locator("text=Assigned Contracts").WaitForAsync(); - var contractsSection = await _page.Locator("text=Assigned Contracts").CountAsync(); - contractsSection.ShouldBeGreaterThan(0, "Contracts tab content should be displayed"); - } - - /// - /// Verify the Assigned Contracts section is visible - /// - public async Task VerifyAssignedContractsSection() - { - await _page.Locator("text=Assigned Contracts").WaitForAsync(); - } - - /// - /// Verify the devices tab content is displayed - /// - public async Task VerifyDevicesTabContent() - { - await _page.Locator("text=Assigned Devices").WaitForAsync(); - var devicesSection = await _page.Locator("text=Assigned Devices").CountAsync(); - devicesSection.ShouldBeGreaterThan(0, "Devices tab content should be displayed"); - } - - /// - /// Verify the Assigned Devices section is visible - /// - public async Task VerifyAssignedDevicesSection() - { - await _page.Locator("text=Assigned Devices").WaitForAsync(); - } - - #endregion - - #region Address Details Verification - - /// - /// Verify address line 1 - /// - public async Task VerifyAddressLine1(string expectedAddress) - { - await _page.Locator("text=Address Line 1").WaitForAsync(); - var addressElement = _page.Locator($"p.text-gray-900:has-text('{expectedAddress}')"); - var addressCount = await addressElement.CountAsync(); - addressCount.ShouldBeGreaterThan(0, $"Address Line 1 should be '{expectedAddress}'"); - } - - /// - /// Verify town - /// - public async Task VerifyTown(string expectedTown) - { - await _page.Locator("text=Town").WaitForAsync(); - var townElement = _page.Locator($"p.text-gray-900:has-text('{expectedTown}')"); - var townCount = await townElement.CountAsync(); - townCount.ShouldBeGreaterThan(0, $"Town should be '{expectedTown}'"); - } - - /// - /// Verify region - /// - public async Task VerifyRegion(string expectedRegion) - { - await _page.Locator("text=Region").WaitForAsync(); - var regionElement = _page.Locator($"p.text-gray-900:has-text('{expectedRegion}')"); - var regionCount = await regionElement.CountAsync(); - regionCount.ShouldBeGreaterThan(0, $"Region should be '{expectedRegion}'"); - } - - /// - /// Verify postal code - /// - public async Task VerifyPostalCode(string expectedPostalCode) - { - await _page.Locator("text=Postal Code").WaitForAsync(); - var postalCodeElement = _page.Locator($"p.text-gray-900:has-text('{expectedPostalCode}')"); - var postalCodeCount = await postalCodeElement.CountAsync(); - postalCodeCount.ShouldBeGreaterThan(0, $"Postal Code should be '{expectedPostalCode}'"); - } - - /// - /// Verify country - /// - public async Task VerifyCountry(string expectedCountry) - { - await _page.Locator("text=Country").WaitForAsync(); - var countryElement = _page.Locator($"p.text-gray-900:has-text('{expectedCountry}')"); - var countryCount = await countryElement.CountAsync(); - countryCount.ShouldBeGreaterThan(0, $"Country should be '{expectedCountry}'"); - } - - #endregion - - #region Contact Details Verification - - /// - /// Verify contact name - /// - public async Task VerifyContactName(string expectedContactName) - { - await _page.Locator("text=Contact Name").WaitForAsync(); - var contactNameElement = _page.Locator($"p.text-gray-900:has-text('{expectedContactName}')"); - var contactNameCount = await contactNameElement.CountAsync(); - contactNameCount.ShouldBeGreaterThan(0, $"Contact Name should be '{expectedContactName}'"); - } - - /// - /// Verify contact email - /// - public async Task VerifyContactEmail(string expectedContactEmail) - { - await _page.Locator("text=Email Address").WaitForAsync(); - var contactEmailElement = _page.Locator($"p.text-gray-900:has-text('{expectedContactEmail}')"); - var contactEmailCount = await contactEmailElement.CountAsync(); - contactEmailCount.ShouldBeGreaterThan(0, $"Contact Email should be '{expectedContactEmail}'"); - } - - /// - /// Verify contact phone - /// - public async Task VerifyContactPhone(string expectedContactPhone) - { - await _page.Locator("text=Phone Number").WaitForAsync(); - var contactPhoneElement = _page.Locator($"p.text-gray-900:has-text('{expectedContactPhone}')"); - var contactPhoneCount = await contactPhoneElement.CountAsync(); - contactPhoneCount.ShouldBeGreaterThan(0, $"Contact Phone should be '{expectedContactPhone}'"); - } - - #endregion - - #region Form Field Verification - - /// - /// Verify merchant name field is visible - /// - public async Task VerifyMerchantNameFieldIsVisible() - { - var nameField = _page.Locator("input[name='MerchantName']"); - await nameField.WaitForAsync(); - var isVisible = await nameField.IsVisibleAsync(); - isVisible.ShouldBeTrue("Merchant name field should be visible"); - } - - /// - /// Verify merchant name field contains expected value - /// - public async Task VerifyMerchantNameFieldContains(string expectedValue) - { - var nameField = _page.Locator("input[name='MerchantName']"); - await nameField.WaitForAsync(); - var fieldValue = await nameField.InputValueAsync(); - fieldValue.ShouldBe(expectedValue, $"Merchant name field should contain '{expectedValue}'"); - } - - /// - /// Verify settlement schedule field is visible - /// - public async Task VerifySettlementScheduleFieldIsVisible() - { - var scheduleField = _page.Locator("select[name='SettlementSchedule']"); - await scheduleField.WaitForAsync(); - var isVisible = await scheduleField.IsVisibleAsync(); - isVisible.ShouldBeTrue("Settlement schedule field should be visible"); - } - - /// - /// Verify address line 1 field is visible - /// - public async Task VerifyAddressLine1FieldIsVisible() - { - var addressField = _page.Locator("input[name='AddressLine1']"); - await addressField.WaitForAsync(); - var isVisible = await addressField.IsVisibleAsync(); - isVisible.ShouldBeTrue("Address line 1 field should be visible"); - } - - /// - /// Verify contact name field is visible - /// - public async Task VerifyContactNameFieldIsVisible() - { - var contactField = _page.Locator("input[name='ContactName']"); - await contactField.WaitForAsync(); - var isVisible = await contactField.IsVisibleAsync(); - isVisible.ShouldBeTrue("Contact name field should be visible"); - } - - /// - /// Verify deposit amount field is visible - /// - public async Task VerifyDepositAmountFieldIsVisible() - { - var amountField = _page.Locator("#depositAmount"); - await amountField.WaitForAsync(); - var isVisible = await amountField.IsVisibleAsync(); - isVisible.ShouldBeTrue("Deposit amount field should be visible"); - } - - /// - /// Verify deposit date field is visible - /// - public async Task VerifyDepositDateFieldIsVisible() - { - var dateField = _page.Locator("#depositDate"); - await dateField.WaitForAsync(); - var isVisible = await dateField.IsVisibleAsync(); - isVisible.ShouldBeTrue("Deposit date field should be visible"); - } - - /// - /// Verify deposit reference field is visible - /// - public async Task VerifyDepositReferenceFieldIsVisible() - { - var referenceField = _page.Locator("#depositReference"); - await referenceField.WaitForAsync(); - var isVisible = await referenceField.IsVisibleAsync(); - isVisible.ShouldBeTrue("Deposit reference field should be visible"); - } - - #endregion - - #region Navigation Actions - - /// - /// Click on a merchant to view its details - /// - public async Task ClickOnMerchant(string merchantName) - { - var merchantRow = _page.Locator($"#merchantList tbody tr:has-text('{merchantName}')"); - await merchantRow.WaitForAsync(); - - // Click the view button for the merchant - var viewButton = merchantRow.Locator("#viewMerchantLink").First; - await viewButton.ClickAsync(); - await _page.WaitForLoadStateAsync(LoadState.NetworkIdle); - } - - /// - /// Click the Add New Merchant button - /// - public async Task ClickAddNewMerchantButton() - { - var addButton = _page.Locator("#newMerchantButton"); - await addButton.WaitForAsync(); - await addButton.ClickAsync(); - await _page.WaitForLoadStateAsync(LoadState.NetworkIdle); - } - - /// - /// Click the Edit button for a specific merchant - /// - public async Task ClickEditForMerchant(string merchantName) - { - var merchantRow = _page.Locator($"#merchantList tbody tr:has-text('{merchantName}')"); - await merchantRow.WaitForAsync(); - - var editButton = merchantRow.Locator("#editMerchantLink").First; - await editButton.ClickAsync(); - await _page.WaitForLoadStateAsync(LoadState.NetworkIdle); - } - - /// - /// Click the Make Deposit button for a specific merchant - /// - public async Task ClickMakeDepositForMerchant(string merchantName) - { - var merchantRow = _page.Locator($"#merchantList tbody tr:has-text('{merchantName}')"); - await merchantRow.WaitForAsync(); - - var depositButton = merchantRow.Locator("#makeDepositLink").First; - await depositButton.ClickAsync(); - await _page.WaitForLoadStateAsync(LoadState.NetworkIdle); - } - - #endregion - - #region Edit Operations - - /// - /// Update merchant name in the edit form - /// - public async Task UpdateMerchantName(string newName) - { - var nameField = _page.Locator("input[name='MerchantName']"); - await nameField.WaitForAsync(); - await nameField.ClearAsync(); - await nameField.FillAsync(newName); - } - - /// - /// Update settlement schedule in the edit form - /// - public async Task UpdateSettlementSchedule(string newSchedule) - { - var scheduleField = _page.Locator("select.input"); - await scheduleField.First.WaitForAsync(); - await scheduleField.First.SelectOptionAsync(new[] { newSchedule }); - } - - /// - /// Click the Save Changes button - /// - public async Task ClickSaveChangesButton() - { - var saveButton = _page.Locator("button:has-text('Save Changes')"); - await saveButton.ClickAsync(); - await Task.Delay(1000); // Wait for save operation - } - - /// - /// Verify success message is displayed - /// - public async Task VerifySuccessMessageIsDisplayed() - { - await _page.Locator(".bg-green-50").WaitForAsync(); - var successMessageCount = await _page.Locator(".bg-green-50").CountAsync(); - successMessageCount.ShouldBeGreaterThan(0, "Success message should be displayed"); - } - - /// - /// Verify success message contains specific text - /// - public async Task VerifySuccessMessageContains(string expectedMessage) - { - var successMessage = _page.Locator(".bg-green-50"); - await successMessage.WaitForAsync(); - var messageText = await successMessage.TextContentAsync(); - messageText.ShouldNotBeNull(); - messageText.ShouldContain(expectedMessage); - } - - /// - /// Update address line 1 - /// - public async Task UpdateAddressLine1(string newAddress) - { - var addressField = _page.Locator("input[name='AddressLine1']"); - await addressField.WaitForAsync(); - await addressField.ClearAsync(); - await addressField.FillAsync(newAddress); - } - - /// - /// Update town - /// - public async Task UpdateTown(string newTown) - { - var townField = _page.Locator("input[name='Town']"); - await townField.WaitForAsync(); - await townField.ClearAsync(); - await townField.FillAsync(newTown); - } - - /// - /// Update region - /// - public async Task UpdateRegion(string newRegion) - { - var regionField = _page.Locator("input[name='Region']"); - await regionField.WaitForAsync(); - await regionField.ClearAsync(); - await regionField.FillAsync(newRegion); - } - - /// - /// Update contact name - /// - public async Task UpdateContactName(string newContactName) - { - var contactNameField = _page.Locator("input[name='ContactName']"); - await contactNameField.WaitForAsync(); - await contactNameField.ClearAsync(); - await contactNameField.FillAsync(newContactName); - } - - /// - /// Update contact email - /// - public async Task UpdateContactEmail(string newEmail) - { - var emailField = _page.Locator("input[name='EmailAddress']"); - await emailField.WaitForAsync(); - await emailField.ClearAsync(); - await emailField.FillAsync(newEmail); - } - - /// - /// Update contact phone - /// - public async Task UpdateContactPhone(string newPhone) - { - var phoneField = _page.Locator("input[name='PhoneNumber']"); - await phoneField.WaitForAsync(); - await phoneField.ClearAsync(); - await phoneField.FillAsync(newPhone); - } - - #endregion - - #region Operator Management - - /// - /// Click the Add Operator button in edit page - /// - public async Task ClickAddOperatorButton() - { - var addButton = _page.Locator("#addOperatorButton"); - await addButton.WaitForAsync(); - await addButton.ClickAsync(); - await Task.Delay(500); // Wait for form to appear - } - - /// - /// Select operator from dropdown - /// - public async Task SelectOperatorFromDropdown(string operatorName) - { - var operatorDropdown = _page.Locator("select").First; - await operatorDropdown.WaitForAsync(); - - // Find the option by text and select it - var options = await operatorDropdown.Locator("option").AllAsync(); - foreach (var option in options) - { - var optionText = await option.TextContentAsync(); - if (optionText != null && optionText.Trim() == operatorName) - { - var value = await option.GetAttributeAsync("value"); - if (!string.IsNullOrEmpty(value)) - { - await operatorDropdown.SelectOptionAsync(new[] { value }); - break; - } - } - } - await Task.Delay(500); // Wait for operator selection to process - } - - /// - /// Enter merchant number - /// - public async Task EnterMerchantNumber(string merchantNumber) - { - var merchantNumberField = _page.Locator("input[placeholder='Enter merchant number']"); - await merchantNumberField.WaitForAsync(); - await merchantNumberField.FillAsync(merchantNumber); - } - - /// - /// Click Add button in operator form - /// - public async Task ClickAddButtonInOperatorForm() - { - // More specific selector for the Add button in the operator form - var addButton = _page.Locator("div.bg-gray-50:has-text('Select Operator') button:has-text('Add')"); - await addButton.ClickAsync(); - await Task.Delay(1000); // Wait for operation to complete - } - - /// - /// Verify operator is listed in assigned operators - /// - public async Task VerifyOperatorIsListedInAssignedOperators(string operatorName) - { - await Task.Delay(500); // Wait for list to update - var operatorElement = _page.Locator($".bg-gray-50:has-text('{operatorName}')"); - var operatorCount = await operatorElement.CountAsync(); - operatorCount.ShouldBeGreaterThan(0, $"Operator '{operatorName}' should be listed in assigned operators"); - } - - /// - /// Remove operator from merchant - /// - public async Task RemoveOperatorFromMerchant(string operatorName) - { - var operatorRow = _page.Locator($".bg-gray-50:has-text('{operatorName}')"); - await operatorRow.WaitForAsync(); - var removeButton = operatorRow.Locator("button:has-text('Remove')"); - await removeButton.ClickAsync(); - await Task.Delay(1000); // Wait for operation to complete - } - - /// - /// Verify operator is not listed in assigned operators - /// - public async Task VerifyOperatorIsNotListedInAssignedOperators(string operatorName) - { - await Task.Delay(500); // Wait for list to update - var operatorElement = _page.Locator($".bg-gray-50 span:has-text('{operatorName}')"); - var operatorCount = await operatorElement.CountAsync(); - operatorCount.ShouldBe(0, $"Operator '{operatorName}' should not be listed in assigned operators"); - } - - #endregion - - #region Contract Management - - /// - /// Click the Assign Contract button in edit page - /// - public async Task ClickAssignContractButton() - { - var assignButton = _page.Locator("#addContractButton"); - await assignButton.WaitForAsync(); - await assignButton.ClickAsync(); - await Task.Delay(500); // Wait for form to appear - } - - /// - /// Select contract from dropdown - /// - public async Task SelectContractFromDropdown(string contractDescription) - { - var contractDropdown = _page.Locator("select").Filter(new LocatorFilterOptions { HasText = "Select a contract" }); - await contractDropdown.First.WaitForAsync(); - - // Select by visible text that contains the contract description - var options = await contractDropdown.First.Locator("option").AllAsync(); - foreach (var option in options) - { - var optionText = await option.TextContentAsync(); - if (optionText != null && optionText.Contains(contractDescription)) - { - var value = await option.GetAttributeAsync("value"); - if (!string.IsNullOrEmpty(value)) - { - await contractDropdown.First.SelectOptionAsync(new[] { value }); - break; - } - } - } - await Task.Delay(500); - } - - /// - /// Click Assign button in contract form - /// - public async Task ClickAssignButtonInContractForm() - { - var assignButton = _page.Locator(".bg-gray-50 button:has-text('Assign')").First; - await assignButton.ClickAsync(); - await Task.Delay(1000); // Wait for operation to complete - } - - /// - /// Verify contract is listed in assigned contracts - /// - public async Task VerifyContractIsListedInAssignedContracts(string contractDescription) - { - await Task.Delay(500); // Wait for list to update - var contractElement = _page.Locator($".bg-gray-50:has-text('{contractDescription}')"); - var contractCount = await contractElement.CountAsync(); - contractCount.ShouldBeGreaterThan(0, $"Contract '{contractDescription}' should be listed in assigned contracts"); - } - - /// - /// Remove contract from merchant - /// - public async Task RemoveContractFromMerchant(string contractDescription) - { - var contractRow = _page.Locator($".bg-gray-50:has-text('{contractDescription}')"); - await contractRow.WaitForAsync(); - var removeButton = contractRow.Locator("button:has-text('Remove')"); - await removeButton.ClickAsync(); - await Task.Delay(1000); // Wait for operation to complete - } - - /// - /// Verify contract is not listed in assigned contracts - /// - public async Task VerifyContractIsNotListedInAssignedContracts(string contractDescription) - { - await Task.Delay(500); // Wait for list to update - var contractElement = _page.Locator($".bg-gray-50 p:has-text('{contractDescription}')"); - var contractCount = await contractElement.CountAsync(); - contractCount.ShouldBe(0, $"Contract '{contractDescription}' should not be listed in assigned contracts"); - } - - #endregion - - #region Device Management - - /// - /// Click the Add Device button in edit page - /// - public async Task ClickAddDeviceButton() - { - var addButton = _page.Locator("#addDeviceButton"); - await addButton.WaitForAsync(); - await addButton.ClickAsync(); - await Task.Delay(500); // Wait for form to appear - } - - /// - /// Enter device identifier - /// - public async Task EnterDeviceIdentifier(string deviceIdentifier) - { - var deviceField = _page.Locator("input[placeholder='Enter device identifier']"); - await deviceField.WaitForAsync(); - await deviceField.FillAsync(deviceIdentifier); - } - - /// - /// Click Add button in device form - /// - public async Task ClickAddButtonInDeviceForm() - { - // More specific selector for the Add button in the device form - var addButton = _page.Locator("div.bg-gray-50:has-text('Device Identifier') button:has-text('Add')"); - await addButton.ClickAsync(); - await Task.Delay(1000); // Wait for operation to complete - } - - /// - /// Verify device is listed in assigned devices - /// - public async Task VerifyDeviceIsListedInAssignedDevices(string deviceIdentifier) - { - await Task.Delay(500); // Wait for list to update - var deviceElement = _page.Locator($".font-mono:has-text('{deviceIdentifier}')"); - var deviceCount = await deviceElement.CountAsync(); - deviceCount.ShouldBeGreaterThan(0, $"Device '{deviceIdentifier}' should be listed in assigned devices"); - } - - /// - /// Remove device from merchant - /// - public async Task RemoveDeviceFromMerchant(string deviceIdentifier) - { - var deviceRow = _page.Locator($".bg-gray-50:has-text('{deviceIdentifier}')"); - await deviceRow.WaitForAsync(); - var removeButton = deviceRow.Locator("button:has-text('Remove')"); - await removeButton.ClickAsync(); - await Task.Delay(1000); // Wait for operation to complete - } - - /// - /// Verify device is not listed in assigned devices - /// - public async Task VerifyDeviceIsNotListedInAssignedDevices(string deviceIdentifier) - { - await Task.Delay(500); // Wait for list to update - var deviceElement = _page.Locator($".font-mono:has-text('{deviceIdentifier}')"); - var deviceCount = await deviceElement.CountAsync(); - deviceCount.ShouldBe(0, $"Device '{deviceIdentifier}' should not be listed in assigned devices"); - } - - #endregion - - #region Deposit Operations - - /// - /// Enter deposit amount - /// - public async Task EnterDepositAmount(string amount) - { - var amountField = _page.Locator("#depositAmount"); - await amountField.WaitForAsync(); - await amountField.FillAsync(amount); - } - - /// - /// Select today as deposit date - /// - public async Task SelectTodayAsDepositDate() - { - var dateField = _page.Locator("#depositDate"); - await dateField.WaitForAsync(); - var today = DateTime.Now.ToString("yyyy-MM-dd"); - await dateField.FillAsync(today); - } - - /// - /// Enter deposit reference - /// - public async Task EnterDepositReference(string reference) - { - var referenceField = _page.Locator("#depositReference"); - await referenceField.WaitForAsync(); - await referenceField.FillAsync(reference); - } - - /// - /// Click the Make Deposit button on deposit page - /// - public async Task ClickMakeDepositButton() - { - var depositButton = _page.Locator("#makeDepositButton"); - await depositButton.WaitForAsync(); - await depositButton.ClickAsync(); - await Task.Delay(1000); // Wait for operation to complete - } - - #endregion -} diff --git a/EstateManagementUI.IntegrationTests/Common/OperatorManagementPageHelper.cs b/EstateManagementUI.IntegrationTests/Common/OperatorManagementPageHelper.cs deleted file mode 100644 index ab459dbb..00000000 --- a/EstateManagementUI.IntegrationTests/Common/OperatorManagementPageHelper.cs +++ /dev/null @@ -1,556 +0,0 @@ -using Microsoft.Playwright; -using Shouldly; - -namespace EstateManagementUI.IntegrationTests.Common; - -/// -/// Helper class for interacting with the Operator Management pages using Playwright -/// -public class OperatorManagementPageHelper -{ - private readonly IPage _page; - private readonly string _baseUrl; - - public OperatorManagementPageHelper(IPage page, string baseUrl) - { - _page = page; - _baseUrl = baseUrl; - } - - #region Navigation - - /// - /// Navigate to the Operator Management page (index) - /// - public async Task NavigateToOperatorManagement() - { - await _page.GotoAsync($"{_baseUrl}/operators"); - await _page.WaitForLoadStateAsync(LoadState.NetworkIdle); - } - - /// - /// Navigate to home page to check menu visibility - /// - public async Task NavigateToHome() - { - await _page.GotoAsync(_baseUrl); - await _page.WaitForLoadStateAsync(LoadState.NetworkIdle); - } - - /// - /// Navigate directly to Edit Operator page for a specific operator - /// - public async Task NavigateToEditOperatorPage(string operatorName) - { - // Get the operator ID based on the name from hardcoded test data - var operatorId = operatorName.Equals("Safaricom", StringComparison.OrdinalIgnoreCase) - ? "33333333-3333-3333-3333-333333333333" - : "33333333-3333-3333-3333-333333333334"; // Voucher - - await _page.GotoAsync($"{_baseUrl}/operators/{operatorId}/edit"); - await _page.WaitForLoadStateAsync(LoadState.NetworkIdle); - } - - #endregion - - #region Menu Visibility Verification - - /// - /// Verify that Operator Management menu is not visible (Administrator role) - /// - public async Task VerifyOperatorManagementMenuIsNotVisible() - { - // Wait a moment for the page to fully load - await Task.Delay(1000); - - var menuLinkCount = await _page.Locator("text=Operator Management").CountAsync(); - menuLinkCount.ShouldBe(0, "Operator Management menu should not be visible for Administrator role"); - } - - /// - /// Verify that Operator Management menu is visible - /// - public async Task VerifyOperatorManagementMenuIsVisible() - { - await _page.Locator("text=Operator Management").WaitForAsync(); - var menuLinkCount = await _page.Locator("text=Operator Management").CountAsync(); - menuLinkCount.ShouldBeGreaterThan(0, "Operator Management menu should be visible"); - } - - #endregion - - #region Page Verification - - /// - /// Verify the Operator Management page is displayed - /// - public async Task VerifyOperatorManagementPageIsDisplayed() - { - await _page.Locator("h1:has-text('Operator Management')").WaitForAsync(); - var heading = await _page.Locator("h1:has-text('Operator Management')").TextContentAsync(); - heading.ShouldNotBeNull(); - heading.ShouldContain("Operator Management"); - } - - /// - /// Verify the page title - /// - public async Task VerifyPageTitle(string expectedTitle) - { - var title = await _page.TitleAsync(); - title.ShouldBe(expectedTitle); - } - - /// - /// Verify the View Operator page is displayed - /// - public async Task VerifyViewOperatorPageIsDisplayed() - { - await _page.Locator("h1:has-text('View Operator')").WaitForAsync(); - var heading = await _page.Locator("h1").TextContentAsync(); - heading.ShouldNotBeNull(); - heading.ShouldContain("View Operator"); - } - - /// - /// Verify the Create New Operator page is displayed - /// - public async Task VerifyCreateNewOperatorPageIsDisplayed() - { - await _page.Locator("h1:has-text('Create New Operator')").WaitForAsync(); - var heading = await _page.Locator("h1:has-text('Create New Operator')").TextContentAsync(); - heading.ShouldNotBeNull(); - heading.ShouldContain("Create New Operator"); - } - - /// - /// Verify the Edit Operator page is displayed - /// - public async Task VerifyEditOperatorPageIsDisplayed() - { - await _page.Locator("h1:has-text('Edit Operator')").WaitForAsync(); - var heading = await _page.Locator("h1").TextContentAsync(); - heading.ShouldNotBeNull(); - heading.ShouldContain("Edit Operator"); - } - - /// - /// Verify an access denied message is displayed - /// - public async Task VerifyAccessDeniedMessageIsDisplayed() - { - await _page.Locator("text=Access Denied").WaitForAsync(); - var heading = await _page.Locator("h3:has-text('Access Denied')").TextContentAsync(); - heading.ShouldNotBeNull(); - heading.ShouldContain("Access Denied"); - } - - /// - /// Verify the access denied message indicates no permission to edit operators - /// - public async Task VerifyAccessDeniedMessageForEditOperators() - { - var message = await _page.Locator("text=You don't have permission to edit operators").TextContentAsync(); - message.ShouldNotBeNull(); - message.ShouldContain("edit operators"); - } - - #endregion - - #region Operator List Verification - - /// - /// Verify the number of operators in the list - /// - public async Task VerifyOperatorListCount(int expectedCount) - { - await _page.Locator("table tbody tr").First.WaitForAsync(); - var operatorRows = await _page.Locator("table tbody tr").CountAsync(); - operatorRows.ShouldBe(expectedCount, $"Expected {expectedCount} operators in the list"); - } - - /// - /// Verify a specific operator is listed - /// - public async Task VerifyOperatorIsListed(string operatorName) - { - var operatorLocator = _page.Locator($"table tbody tr:has-text('{operatorName}')"); - await operatorLocator.WaitForAsync(); - var count = await operatorLocator.CountAsync(); - count.ShouldBeGreaterThan(0, $"Operator '{operatorName}' should be listed"); - } - - /// - /// Verify operator custom merchant number requirement status - /// - public async Task VerifyOperatorCustomMerchantNumberRequirement(string operatorName, string expectedStatus) - { - var operatorRow = _page.Locator($"table tbody tr:has-text('{operatorName}')"); - await operatorRow.WaitForAsync(); - - var statusText = await operatorRow.Locator("td:nth-child(2)").TextContentAsync(); - statusText.ShouldNotBeNull(); - statusText.ShouldContain(expectedStatus); - } - - /// - /// Verify operator custom terminal number requirement status - /// - public async Task VerifyOperatorCustomTerminalNumberRequirement(string operatorName, string expectedStatus) - { - var operatorRow = _page.Locator($"table tbody tr:has-text('{operatorName}')"); - await operatorRow.WaitForAsync(); - - var statusText = await operatorRow.Locator("td:nth-child(3)").TextContentAsync(); - statusText.ShouldNotBeNull(); - statusText.ShouldContain(expectedStatus); - } - - #endregion - - #region Button Visibility Verification - - /// - /// Verify Add New Operator button is visible - /// - public async Task VerifyAddNewOperatorButtonIsVisible() - { - var button = _page.Locator("#newOperatorButton"); - await button.WaitForAsync(); - var isVisible = await button.IsVisibleAsync(); - isVisible.ShouldBeTrue("Add New Operator button should be visible"); - } - - /// - /// Verify Add New Operator button is not visible - /// - public async Task VerifyAddNewOperatorButtonIsNotVisible() - { - await Task.Delay(1000); // Wait for page to fully render - var buttonCount = await _page.Locator("#newOperatorButton").CountAsync(); - buttonCount.ShouldBe(0, "Add New Operator button should not be visible"); - } - - /// - /// Verify Edit Operator button is visible on view page - /// - public async Task VerifyEditOperatorButtonIsVisible() - { - var button = _page.Locator("button:has-text('Edit Operator')"); - await button.WaitForAsync(); - var isVisible = await button.IsVisibleAsync(); - isVisible.ShouldBeTrue("Edit Operator button should be visible"); - } - - /// - /// Verify Edit button is visible for a specific operator in the list - /// - public async Task VerifyEditButtonIsVisibleForOperator(string operatorName) - { - var operatorRow = _page.Locator($"table tbody tr:has-text('{operatorName}')"); - await operatorRow.WaitForAsync(); - - var editButton = operatorRow.Locator("button[title='Edit']"); - var isVisible = await editButton.IsVisibleAsync(); - isVisible.ShouldBeTrue($"Edit button should be visible for operator '{operatorName}'"); - } - - /// - /// Verify Edit button is not visible for a specific operator in the list - /// - public async Task VerifyEditButtonIsNotVisibleForOperator(string operatorName) - { - var operatorRow = _page.Locator($"table tbody tr:has-text('{operatorName}')"); - await operatorRow.WaitForAsync(); - - var editButtonCount = await operatorRow.Locator("button[title='Edit']").CountAsync(); - editButtonCount.ShouldBe(0, $"Edit button should not be visible for operator '{operatorName}'"); - } - - #endregion - - #region Operator Detail Verification - - /// - /// Verify the operator name on the view page - /// - public async Task VerifyOperatorName(string expectedName) - { - var nameLocator = _page.Locator("h1:has-text('View Operator')"); - await nameLocator.WaitForAsync(); - var heading = await nameLocator.TextContentAsync(); - heading.ShouldNotBeNull(); - heading.ShouldContain(expectedName); - } - - /// - /// Verify operator custom merchant number requirement on detail page - /// - public async Task VerifyOperatorCustomMerchantNumberRequirementDetail(string expectedStatus) - { - // Find the div containing the label, then look for the status badge within it - var sectionDiv = _page.Locator("div:has(label:has-text('Require Custom Merchant Number'))"); - await sectionDiv.WaitForAsync(); - - var statusBadge = sectionDiv.Locator($"span:has-text('{expectedStatus}')"); - await statusBadge.WaitForAsync(); - var isVisible = await statusBadge.IsVisibleAsync(); - isVisible.ShouldBeTrue($"Custom merchant number requirement should show '{expectedStatus}'"); - } - - /// - /// Verify operator custom terminal number requirement on detail page - /// - public async Task VerifyOperatorCustomTerminalNumberRequirementDetail(string expectedStatus) - { - // Find the div containing the label, then look for the status badge within it - var sectionDiv = _page.Locator("div:has(label:has-text('Require Custom Terminal Number'))"); - await sectionDiv.WaitForAsync(); - - var statusBadge = sectionDiv.Locator($"span:has-text('{expectedStatus}')"); - await statusBadge.WaitForAsync(); - var isVisible = await statusBadge.IsVisibleAsync(); - isVisible.ShouldBeTrue($"Custom terminal number requirement should show '{expectedStatus}'"); - } - - #endregion - - #region Form Field Verification - - /// - /// Verify operator name field is visible - /// - public async Task VerifyOperatorNameFieldIsVisible() - { - var field = _page.Locator("input[placeholder='Enter operator name']"); - await field.WaitForAsync(); - var isVisible = await field.IsVisibleAsync(); - isVisible.ShouldBeTrue("Operator name field should be visible"); - } - - /// - /// Verify operator name field contains expected value - /// - public async Task VerifyOperatorNameFieldContains(string expectedValue) - { - var field = _page.Locator("input[placeholder='Enter operator name']"); - await field.WaitForAsync(); - var value = await field.InputValueAsync(); - value.ShouldBe(expectedValue, $"Operator name field should contain '{expectedValue}'"); - } - - /// - /// Verify custom merchant number checkbox is visible - /// - public async Task VerifyCustomMerchantNumberCheckboxIsVisible() - { - var label = _page.Locator("label:has-text('Require Custom Merchant Number')"); - await label.WaitForAsync(); - var checkbox = label.Locator("input[type='checkbox']"); - var isVisible = await checkbox.IsVisibleAsync(); - isVisible.ShouldBeTrue("Custom merchant number checkbox should be visible"); - } - - /// - /// Verify custom terminal number checkbox is visible - /// - public async Task VerifyCustomTerminalNumberCheckboxIsVisible() - { - var label = _page.Locator("label:has-text('Require Custom Terminal Number')"); - await label.WaitForAsync(); - var checkbox = label.Locator("input[type='checkbox']"); - var isVisible = await checkbox.IsVisibleAsync(); - isVisible.ShouldBeTrue("Custom terminal number checkbox should be visible"); - } - - #endregion - - #region Navigation Actions - - /// - /// Click on a specific operator in the list - /// - public async Task ClickOnOperator(string operatorName) - { - var operatorRow = _page.Locator($"table tbody tr:has-text('{operatorName}')"); - await operatorRow.WaitForAsync(); - await operatorRow.ClickAsync(); - await _page.WaitForLoadStateAsync(LoadState.NetworkIdle); - } - - /// - /// Click the Add New Operator button - /// - public async Task ClickAddNewOperatorButton() - { - var button = _page.Locator("#newOperatorButton"); - await button.WaitForAsync(); - await button.ClickAsync(); - await _page.WaitForLoadStateAsync(LoadState.NetworkIdle); - } - - /// - /// Click edit button for a specific operator - /// - public async Task ClickEditForOperator(string operatorName) - { - var operatorRow = _page.Locator($"table tbody tr:has-text('{operatorName}')"); - await operatorRow.WaitForAsync(); - - var editButton = operatorRow.Locator("button[title='Edit']"); - await editButton.WaitForAsync(); - await editButton.ClickAsync(); - await _page.WaitForLoadStateAsync(LoadState.NetworkIdle); - } - - /// - /// Click the Edit Operator button on the view page - /// - public async Task ClickEditOperatorButton() - { - var button = _page.Locator("button:has-text('Edit Operator')"); - await button.WaitForAsync(); - await button.ClickAsync(); - await _page.WaitForLoadStateAsync(LoadState.NetworkIdle); - } - - #endregion - - #region Edit Operations - - /// - /// Update the operator name - /// - public async Task UpdateOperatorName(string newName) - { - var field = _page.Locator("input[placeholder='Enter operator name']"); - await field.WaitForAsync(); - await field.ClearAsync(); - await field.FillAsync(newName); - } - - /// - /// Update the custom merchant number requirement checkbox - /// - public async Task UpdateCustomMerchantNumberRequirement(bool isChecked) - { - var label = _page.Locator("label:has-text('Require Custom Merchant Number')"); - await label.WaitForAsync(); - var checkbox = label.Locator("input[type='checkbox']"); - - var currentState = await checkbox.IsCheckedAsync(); - if (currentState != isChecked) - { - await checkbox.ClickAsync(); - } - } - - /// - /// Update the custom terminal number requirement checkbox - /// - public async Task UpdateCustomTerminalNumberRequirement(bool isChecked) - { - var label = _page.Locator("label:has-text('Require Custom Terminal Number')"); - await label.WaitForAsync(); - var checkbox = label.Locator("input[type='checkbox']"); - - var currentState = await checkbox.IsCheckedAsync(); - if (currentState != isChecked) - { - await checkbox.ClickAsync(); - } - } - - /// - /// Click the Save Changes button (Update Operator button) - /// - public async Task ClickSaveChangesButton() - { - var button = _page.Locator("button[type='submit']:has-text('Update Operator')"); - await button.WaitForAsync(); - await button.ClickAsync(); - await Task.Delay(2000); // Wait for the operation to complete - } - - /// - /// Click the Create Operator button - /// - public async Task ClickCreateOperatorButton() - { - var button = _page.Locator("#createOperatorButton"); - await button.WaitForAsync(); - await button.ClickAsync(); - await Task.Delay(2000); // Wait for the operation to complete - } - - /// - /// Enter operator name - /// - public async Task EnterOperatorName(string operatorName) - { - var field = _page.Locator("input[placeholder='Enter operator name']"); - await field.WaitForAsync(); - await field.FillAsync(operatorName); - } - - #endregion - - #region Success/Error Message Verification - - /// - /// Verify a success message is displayed - /// - public async Task VerifySuccessMessageIsDisplayed() - { - var successMessage = _page.Locator(".bg-green-50"); - await successMessage.WaitForAsync(); - var isVisible = await successMessage.IsVisibleAsync(); - isVisible.ShouldBeTrue("Success message should be displayed"); - } - - /// - /// Verify success message contains expected text - /// - public async Task VerifySuccessMessageContains(string expectedMessage) - { - var successMessage = _page.Locator(".bg-green-50"); - await successMessage.WaitForAsync(); - var messageText = await successMessage.TextContentAsync(); - messageText.ShouldNotBeNull(); - messageText.ShouldContain(expectedMessage); - } - - /// - /// Verify user was redirected to operator list (after create operation) - /// - public async Task VerifyRedirectedToOperatorList() - { - await Task.Delay(1000); - var currentUrl = _page.Url; - currentUrl.ShouldEndWith("/operators"); - } - - /// - /// Verify a validation error is displayed - /// - public async Task VerifyValidationErrorIsDisplayed() - { - var errorMessage = _page.Locator(".text-red-600"); - await errorMessage.WaitForAsync(); - var isVisible = await errorMessage.IsVisibleAsync(); - isVisible.ShouldBeTrue("Validation error should be displayed"); - } - - /// - /// Verify validation error is displayed for operator name - /// - public async Task VerifyValidationErrorForOperatorName() - { - var errorMessage = _page.Locator(".text-red-600:has-text('required')"); - await errorMessage.WaitForAsync(); - var isVisible = await errorMessage.IsVisibleAsync(); - isVisible.ShouldBeTrue("Validation error for operator name should be displayed"); - } - - #endregion -} diff --git a/EstateManagementUI.IntegrationTests/Common/ReportingPageHelper.cs b/EstateManagementUI.IntegrationTests/Common/ReportingPageHelper.cs deleted file mode 100644 index 266bb367..00000000 --- a/EstateManagementUI.IntegrationTests/Common/ReportingPageHelper.cs +++ /dev/null @@ -1,703 +0,0 @@ -using Microsoft.Playwright; -using Shouldly; - -namespace EstateManagementUI.IntegrationTests.Common; - -/// -/// Helper class for interacting with Reporting pages using Playwright -/// -public class ReportingPageHelper -{ - private readonly IPage _page; - private readonly string _baseUrl; - private const int DefaultChartWaitTimeoutMs = 5000; - - public ReportingPageHelper(IPage page, string baseUrl) - { - _page = page; - _baseUrl = baseUrl; - } - - #region Private Helpers - - /// - /// Wait for a canvas element to be visible (used for chart rendering) - /// - private async Task WaitForCanvasAsync() - { - await _page.Locator("canvas").First.WaitForAsync(new LocatorWaitForOptions - { - State = WaitForSelectorState.Visible, - Timeout = DefaultChartWaitTimeoutMs - }); - } - - #endregion - - #region Navigation - - /// - /// Navigate to the Reporting Dashboard - /// - public async Task NavigateToReportingDashboard() - { - await _page.GotoAsync($"{_baseUrl}/reporting"); - await _page.WaitForLoadStateAsync(LoadState.NetworkIdle); - } - - /// - /// Navigate to the Transaction Detail Report - /// - public async Task NavigateToTransactionDetailReport() - { - await _page.GotoAsync($"{_baseUrl}/reporting/transaction-detail"); - await _page.WaitForLoadStateAsync(LoadState.NetworkIdle); - } - - /// - /// Navigate to the Transaction Summary by Merchant Report - /// - public async Task NavigateToTransactionSummaryMerchantReport() - { - await _page.GotoAsync($"{_baseUrl}/reporting/transaction-summary-merchant"); - await _page.WaitForLoadStateAsync(LoadState.NetworkIdle); - } - - /// - /// Navigate to the Transaction Summary by Operator Report - /// - public async Task NavigateToTransactionSummaryOperatorReport() - { - await _page.GotoAsync($"{_baseUrl}/reporting/transaction-summary-operator"); - await _page.WaitForLoadStateAsync(LoadState.NetworkIdle); - } - - /// - /// Navigate to the Product Performance Report - /// - public async Task NavigateToProductPerformanceReport() - { - await _page.GotoAsync($"{_baseUrl}/reporting/product-performance"); - await _page.WaitForLoadStateAsync(LoadState.NetworkIdle); - } - - /// - /// Navigate to the Settlement Summary Report - /// - public async Task NavigateToSettlementSummaryReport() - { - await _page.GotoAsync($"{_baseUrl}/reporting/settlement-summary"); - await _page.WaitForLoadStateAsync(LoadState.NetworkIdle); - } - - /// - /// Navigate to the Settlement Reconciliation Report - /// - public async Task NavigateToSettlementReconciliationReport() - { - await _page.GotoAsync($"{_baseUrl}/reporting/settlement-reconciliation"); - await _page.WaitForLoadStateAsync(LoadState.NetworkIdle); - } - - /// - /// Navigate to the Merchant Settlement History Report - /// - public async Task NavigateToMerchantSettlementHistoryReport() - { - await _page.GotoAsync($"{_baseUrl}/reporting/merchant-settlement-history"); - await _page.WaitForLoadStateAsync(LoadState.NetworkIdle); - } - - /// - /// Navigate to the Analytical Charts Report - /// - public async Task NavigateToAnalyticalChartsReport() - { - await _page.GotoAsync($"{_baseUrl}/reporting/analytical-charts"); - await _page.WaitForLoadStateAsync(LoadState.NetworkIdle); - } - - #endregion - - #region Reporting Dashboard Verification - - /// - /// Verify the Reporting Dashboard page is displayed - /// - public async Task VerifyReportingDashboardPageIsDisplayed() - { - var heading = await _page.Locator("h1:has-text('Reporting Dashboard')").TextContentAsync(); - heading.ShouldNotBeNull(); - heading.ShouldContain("Reporting Dashboard"); - } - - /// - /// Verify the page title - /// - public async Task VerifyPageTitle(string expectedTitle) - { - var title = await _page.TitleAsync(); - title.ShouldBe(expectedTitle); - } - - /// - /// Verify the Transaction Reporting section is displayed - /// - public async Task VerifyTransactionReportingSectionIsDisplayed() - { - await _page.Locator("h3:has-text('Transaction Reporting')").WaitForAsync(); - var section = await _page.Locator("h3:has-text('Transaction Reporting')").IsVisibleAsync(); - section.ShouldBeTrue("Transaction Reporting section should be visible"); - } - - /// - /// Verify the Settlement Reporting section is displayed - /// - public async Task VerifySettlementReportingSectionIsDisplayed() - { - await _page.Locator("h3:has-text('Settlement Reporting')").WaitForAsync(); - var section = await _page.Locator("h3:has-text('Settlement Reporting')").IsVisibleAsync(); - section.ShouldBeTrue("Settlement Reporting section should be visible"); - } - - /// - /// Verify the Reconciliation section is displayed - /// - public async Task VerifyReconciliationSectionIsDisplayed() - { - await _page.Locator("h3:has-text('Reconciliation')").WaitForAsync(); - var section = await _page.Locator("h3:has-text('Reconciliation')").IsVisibleAsync(); - section.ShouldBeTrue("Reconciliation section should be visible"); - } - - /// - /// Verify the KPI Reporting section is displayed - /// - public async Task VerifyKpiReportingSectionIsDisplayed() - { - await _page.Locator("h3:has-text('KPI Reporting')").WaitForAsync(); - var section = await _page.Locator("h3:has-text('KPI Reporting')").IsVisibleAsync(); - section.ShouldBeTrue("KPI Reporting section should be visible"); - } - - #endregion - - #region Report Page Verification - - /// - /// Verify a report page is displayed by checking for a heading - /// - public async Task VerifyReportPageIsDisplayed(string pageHeading) - { - await _page.Locator($"h1:has-text('{pageHeading}')").WaitForAsync(); - var heading = await _page.Locator($"h1:has-text('{pageHeading}')").IsVisibleAsync(); - heading.ShouldBeTrue($"{pageHeading} page should be displayed"); - } - - /// - /// Verify the filters section is displayed - /// - public async Task VerifyFiltersSectionIsDisplayed() - { - await _page.Locator("h3:has-text('Filters')").WaitForAsync(); - var section = await _page.Locator("h3:has-text('Filters')").IsVisibleAsync(); - section.ShouldBeTrue("Filters section should be visible"); - } - - /// - /// Verify a data grid is displayed - /// - public async Task VerifyDataGridIsDisplayed() - { - await _page.Locator("table.table").WaitForAsync(); - var table = await _page.Locator("table.table").IsVisibleAsync(); - table.ShouldBeTrue("Data grid should be visible"); - } - - /// - /// Verify transaction details grid is displayed - /// - public async Task VerifyTransactionDetailsGridIsDisplayed() - { - await VerifyDataGridIsDisplayed(); - } - - /// - /// Verify merchant summary grid is displayed - /// - public async Task VerifyMerchantSummaryGridIsDisplayed() - { - await VerifyDataGridIsDisplayed(); - } - - /// - /// Verify operator summary grid is displayed - /// - public async Task VerifyOperatorSummaryGridIsDisplayed() - { - await VerifyDataGridIsDisplayed(); - } - - /// - /// Verify product performance grid is displayed - /// - public async Task VerifyProductPerformanceGridIsDisplayed() - { - await VerifyDataGridIsDisplayed(); - } - - /// - /// Verify settlement summary grid is displayed - /// - public async Task VerifySettlementSummaryGridIsDisplayed() - { - await VerifyDataGridIsDisplayed(); - } - - /// - /// Verify reconciliation grid is displayed - /// - public async Task VerifyReconciliationGridIsDisplayed() - { - await VerifyDataGridIsDisplayed(); - } - - /// - /// Verify settlement history grid is displayed - /// - public async Task VerifySettlementHistoryGridIsDisplayed() - { - await VerifyDataGridIsDisplayed(); - } - - /// - /// Verify analytical charts are displayed - /// - public async Task VerifyAnalyticalChartsAreDisplayed() - { - // Wait for canvas elements to be present and visible - await WaitForCanvasAsync(); - var chartCanvas = await _page.Locator("canvas").CountAsync(); - chartCanvas.ShouldBeGreaterThan(0, "At least one chart should be displayed"); - } - - #endregion - - #region KPI Verification - - /// - /// Verify a specific KPI is displayed - /// - public async Task VerifyKpiIsDisplayed(string kpiName) - { - await _page.Locator($".info-box-text:has-text('{kpiName}')").WaitForAsync(); - var kpi = await _page.Locator($".info-box-text:has-text('{kpiName}')").IsVisibleAsync(); - kpi.ShouldBeTrue($"{kpiName} KPI should be visible"); - } - - /// - /// Verify Total Transactions KPI is greater than a value - /// - public async Task VerifyTotalTransactionsKpiIsGreaterThan(int minValue) - { - var kpiBox = _page.Locator(".info-box").Filter(new LocatorFilterOptions - { - HasText = "Total Transactions" - }); - await kpiBox.WaitForAsync(); - - var kpiValue = await kpiBox.Locator(".info-box-number").TextContentAsync(); - kpiValue.ShouldNotBeNull(); - - // Remove any commas or formatting - var cleanValue = kpiValue.Replace(",", "").Trim(); - var value = int.Parse(cleanValue); - value.ShouldBeGreaterThan(minValue, $"Total Transactions should be greater than {minValue}"); - } - - #endregion - - #region Filter Interactions - - /// - /// Set the start date filter - /// - public async Task SetStartDate(int daysAgo) - { - var date = DateTime.Now.AddDays(-daysAgo); - var dateString = date.ToString("yyyy-MM-dd"); - - var startDateInput = _page.Locator("input[type='date']").First; - await startDateInput.FillAsync(dateString); - } - - /// - /// Set the end date filter to today - /// - public async Task SetEndDateToToday() - { - var dateString = DateTime.Now.ToString("yyyy-MM-dd"); - - var endDateInput = _page.Locator("input[type='date']").Nth(1); - await endDateInput.FillAsync(dateString); - } - - /// - /// Select a merchant from the filter dropdown - /// - public async Task SelectMerchantFromFilter() - { - var merchantDropdown = _page.Locator("select").Filter(new LocatorFilterOptions - { - Has = _page.Locator("option:has-text('All Merchants')") - }); - - // Get the first available merchant option (not "All Merchants") - var options = await merchantDropdown.Locator("option").AllAsync(); - if (options.Count > 1) - { - var firstMerchantValue = await options[1].GetAttributeAsync("value"); - if (!string.IsNullOrEmpty(firstMerchantValue)) - { - await merchantDropdown.SelectOptionAsync(firstMerchantValue); - } - } - } - - /// - /// Select an operator from the filter dropdown - /// - public async Task SelectOperatorFromFilter() - { - var operatorDropdown = _page.Locator("select").Filter(new LocatorFilterOptions - { - Has = _page.Locator("option:has-text('All Operators')") - }); - - // Get the first available operator option (not "All Operators") - var options = await operatorDropdown.Locator("option").AllAsync(); - if (options.Count > 1) - { - var firstOperatorValue = await options[1].GetAttributeAsync("value"); - if (!string.IsNullOrEmpty(firstOperatorValue)) - { - await operatorDropdown.SelectOptionAsync(firstOperatorValue); - } - } - } - - /// - /// Select a product from the filter dropdown - /// - public async Task SelectProductFromFilter() - { - var productDropdown = _page.Locator("select").Filter(new LocatorFilterOptions - { - Has = _page.Locator("option:has-text('All Products')") - }); - - // Get the first available product option (not "All Products") - var options = await productDropdown.Locator("option").AllAsync(); - if (options.Count > 1) - { - var firstProductValue = await options[1].GetAttributeAsync("value"); - if (!string.IsNullOrEmpty(firstProductValue)) - { - await productDropdown.SelectOptionAsync(firstProductValue); - } - } - } - - /// - /// Select a status from the filter dropdown - /// - public async Task SelectStatusFromFilter(string status) - { - var statusDropdown = _page.Locator("select").Filter(new LocatorFilterOptions - { - Has = _page.Locator("option:has-text('All Statuses')") - }); - - await statusDropdown.SelectOptionAsync(new[] { status }); - } - - /// - /// Click the Apply Filters button - /// - public async Task ClickApplyFilters() - { - await _page.Locator("button:has-text('Apply Filters')").ClickAsync(); - await _page.WaitForLoadStateAsync(LoadState.NetworkIdle); - } - - /// - /// Click the Clear Filters button - /// - public async Task ClickClearFilters() - { - await _page.Locator("button:has-text('Clear Filters')").ClickAsync(); - await _page.WaitForLoadStateAsync(LoadState.NetworkIdle); - } - - /// - /// Click the Refresh button - /// - public async Task ClickRefresh() - { - await _page.Locator("button:has-text('Refresh')").ClickAsync(); - await _page.WaitForLoadStateAsync(LoadState.NetworkIdle); - } - - #endregion - - #region Data Verification - - /// - /// Verify filtered results are displayed - /// - public async Task VerifyFilteredResultsDisplayed() - { - // Wait for the table to be visible - await _page.Locator("table.table tbody tr").First.WaitForAsync(); - - // Verify at least one row exists - var rowCount = await _page.Locator("table.table tbody tr").CountAsync(); - rowCount.ShouldBeGreaterThan(0, "At least one result should be displayed after filtering"); - } - - /// - /// Verify all displayed transactions match the selected merchant - /// - public async Task VerifyAllTransactionsMatchSelectedMerchant() - { - // This is a placeholder - in a real scenario, we would store the selected merchant name - // and verify each row matches it - await VerifyFilteredResultsDisplayed(); - } - - /// - /// Verify all displayed transactions match the selected operator - /// - public async Task VerifyAllTransactionsMatchSelectedOperator() - { - // This is a placeholder - in a real scenario, we would store the selected operator name - // and verify each row matches it - await VerifyFilteredResultsDisplayed(); - } - - /// - /// Verify all displayed transactions match the selected product - /// - public async Task VerifyAllTransactionsMatchSelectedProduct() - { - // This is a placeholder - in a real scenario, we would store the selected product name - // and verify each row matches it - await VerifyFilteredResultsDisplayed(); - } - - /// - /// Verify filters are reset to default values - /// - public async Task VerifyFiltersAreResetToDefaultValues() - { - // Verify merchant dropdown is reset to "All Merchants" - var merchantDropdown = _page.Locator("select").Filter(new LocatorFilterOptions - { - Has = _page.Locator("option:has-text('All Merchants')") - }); - var merchantValue = await merchantDropdown.InputValueAsync(); - merchantValue.ShouldBe("", "Merchant filter should be reset"); - } - - /// - /// Verify unfiltered results are displayed - /// - public async Task VerifyUnfilteredResultsDisplayed() - { - await VerifyFilteredResultsDisplayed(); - } - - #endregion - - #region Sorting and Pagination - - /// - /// Click on a column header to sort - /// - public async Task ClickColumnHeader(string columnName) - { - await _page.Locator($"th:has-text('{columnName}')").ClickAsync(); - // Wait for the sort icon to update or the table to reload - await _page.WaitForLoadStateAsync(LoadState.DOMContentLoaded); - } - - /// - /// Verify grid is sorted by column in ascending order - /// - public async Task VerifyGridIsSortedByColumnAscending(string columnName) - { - // In a real scenario, we would verify the actual data is sorted - // For now, just verify the column is still visible - var column = await _page.Locator($"th:has-text('{columnName}')").IsVisibleAsync(); - column.ShouldBeTrue($"{columnName} column should be visible"); - } - - /// - /// Verify grid has multiple pages - /// - public async Task VerifyGridHasMultiplePages() - { - // Check if pagination controls are visible - var nextButton = await _page.Locator("button[title='Next page']").IsVisibleAsync(); - nextButton.ShouldBeTrue("Next page button should be visible when multiple pages exist"); - } - - /// - /// Click the Next Page button - /// - public async Task ClickNextPageButton() - { - await _page.Locator("button[title='Next page']").ClickAsync(); - // Wait for the page to update - await _page.WaitForLoadStateAsync(LoadState.DOMContentLoaded); - } - - /// - /// Verify next page of results is displayed - /// - public async Task VerifyNextPageOfResultsDisplayed() - { - // Verify we're on page 2 or greater - var pageInfo = await _page.Locator("span:has-text('Page')").TextContentAsync(); - pageInfo.ShouldNotBeNull(); - pageInfo.ShouldNotContain("Page 1 of 1"); - } - - #endregion - - #region View Toggle - - /// - /// Click the Chart View button - /// - public async Task ClickChartViewButton() - { - await _page.Locator("button:has-text('Chart View')").ClickAsync(); - // Wait for chart to be rendered - await WaitForCanvasAsync(); - } - - /// - /// Click the Grid View button - /// - public async Task ClickGridViewButton() - { - await _page.Locator("button:has-text('Grid View')").ClickAsync(); - // Wait for the table to be rendered - await _page.Locator("table.table").WaitForAsync(); - } - - /// - /// Verify product performance chart is displayed - /// - public async Task VerifyProductPerformanceChartIsDisplayed() - { - // Wait for canvas elements to be present and visible - await WaitForCanvasAsync(); - var chartCanvas = await _page.Locator("canvas").CountAsync(); - chartCanvas.ShouldBeGreaterThan(0, "Chart should be displayed"); - } - - #endregion - - #region Chart Type Selection - - /// - /// Select a chart type - /// - public async Task SelectChartType(string chartType) - { - // In the Analytical Charts report, there might be buttons or dropdowns to select chart types - var chartTypeButton = _page.Locator($"button:has-text('{chartType}')"); - var buttonExists = await chartTypeButton.CountAsync(); - - if (buttonExists > 0) - { - await chartTypeButton.ClickAsync(); - // Wait for canvas to update - await WaitForCanvasAsync(); - } - } - - /// - /// Verify volume chart is displayed - /// - public async Task VerifyVolumeChartIsDisplayed() - { - await VerifyAnalyticalChartsAreDisplayed(); - } - - /// - /// Verify value chart is displayed - /// - public async Task VerifyValueChartIsDisplayed() - { - await VerifyAnalyticalChartsAreDisplayed(); - } - - #endregion - - #region Drill-Down - - /// - /// Click View Details for a merchant - /// - public async Task ClickViewDetailsForMerchant() - { - // Find the first "View Details" button in the merchant summary - var viewDetailsButton = _page.Locator("button:has-text('View Details')").First; - await viewDetailsButton.WaitForAsync(); - await viewDetailsButton.ClickAsync(); - await _page.WaitForLoadStateAsync(LoadState.NetworkIdle); - } - - /// - /// Verify user is navigated to Transaction Detail Report - /// - public async Task VerifyNavigatedToTransactionDetailReport() - { - await _page.Locator("h1:has-text('Transaction Detail Report')").WaitForAsync(); - var heading = await _page.Locator("h1:has-text('Transaction Detail Report')").IsVisibleAsync(); - heading.ShouldBeTrue("Should be navigated to Transaction Detail Report"); - } - - /// - /// Verify merchant filter is pre-populated - /// - public async Task VerifyMerchantFilterIsPrePopulated() - { - // Check if a merchant is selected in the dropdown (value is not empty) - var merchantDropdown = _page.Locator("select").Filter(new LocatorFilterOptions - { - Has = _page.Locator("option:has-text('All Merchants')") - }); - var merchantValue = await merchantDropdown.InputValueAsync(); - merchantValue.ShouldNotBe("", "Merchant filter should be pre-populated"); - } - - #endregion - - #region Settlement Specific - - /// - /// Verify only settled settlements are displayed - /// - public async Task VerifyOnlySettledSettlementsDisplayed() - { - // This would require checking the status column in each row - // For now, just verify filtered results are displayed - await VerifyFilteredResultsDisplayed(); - } - - #endregion -} diff --git a/EstateManagementUI.IntegrationTests/EstateManagementUI.IntegrationTests.csproj b/EstateManagementUI.IntegrationTests/EstateManagementUI.IntegrationTests.csproj index 66804ec7..5f695b9a 100644 --- a/EstateManagementUI.IntegrationTests/EstateManagementUI.IntegrationTests.csproj +++ b/EstateManagementUI.IntegrationTests/EstateManagementUI.IntegrationTests.csproj @@ -1,4 +1,4 @@ - + net10.0 @@ -10,6 +10,8 @@ + + @@ -17,11 +19,16 @@ + + + all runtime; build; native; contentfiles; analyzers; buildtransitive + + @@ -36,4 +43,8 @@ + + + + diff --git a/EstateManagementUI.IntegrationTests/Features/ContractManagement.feature b/EstateManagementUI.IntegrationTests/Features/ContractManagement.feature deleted file mode 100644 index f8680164..00000000 --- a/EstateManagementUI.IntegrationTests/Features/ContractManagement.feature +++ /dev/null @@ -1,186 +0,0 @@ -Feature: Contract Management Integration Tests - As a user of the Estate Management UI - I want to manage contracts based on my role - So that I can view, create, and edit contracts according to my permissions - -Background: - Given the user navigates to the Contract Management page - -@ContractManagement @AdminRole -Scenario: Administrator user cannot see Contract Management menu - Given the user is authenticated as an "Administrator" user - When the user navigates to the home page - Then the Contract Management menu item is not visible - -@ContractManagement @AdminRole -Scenario: Administrator user cannot access Contract Management page directly - Given the user is authenticated as an "Administrator" user - When the user navigates to the Contract Management page - Then an access denied message is displayed - -@ContractManagement @EstateRole -Scenario: Estate user can see Contract Management menu - Given the user is authenticated as an "Estate" user - When the user navigates to the home page - Then the Contract Management menu item is visible - -@ContractManagement @EstateRole -Scenario: Estate user can view contracts list - Given the user is authenticated as an "Estate" user - When the user navigates to the Contract Management page - Then the Contract Management page is displayed - And the page title is "Contract Management" - And "2" contracts are displayed in the list - And the "Add New Contract" button is visible - -@ContractManagement @EstateRole -Scenario: Estate user can view contract details - Given the user is authenticated as an "Estate" user - When the user navigates to the Contract Management page - And the user clicks on the "View" button for the first contract - Then the View Contract page is displayed - And the contract description is "Standard Transaction Contract" - And the contract operator is "Safaricom" - And the contract has "2" products - And the first product is "Mobile Topup" - And the first product has "2" transaction fees - -@ContractManagement @EstateRole -Scenario: Estate user can view product transaction fee details - Given the user is authenticated as an "Estate" user - When the user navigates to the Contract Management page - And the user clicks on the "View" button for the first contract - Then the View Contract page is displayed - And the product "Mobile Topup" has a transaction fee "Merchant Commission" with value "0.50" - And the product "Mobile Topup" has a transaction fee "Service Provider Fee" with value "2.50" - -@ContractManagement @EstateRole -Scenario: Estate user can navigate to create new contract page - Given the user is authenticated as an "Estate" user - When the user navigates to the Contract Management page - And the user clicks on the "Add New Contract" button - Then the Create New Contract page is displayed - And the contract form is displayed - And the "Description" field is visible - And the "Operator" dropdown is visible - -@ContractManagement @EstateRole -Scenario: Estate user can create a new contract - Given the user is authenticated as an "Estate" user - When the user navigates to the Create New Contract page - And the user enters "Test Contract" in the "Description" field - And the user selects "Safaricom" from the "Operator" dropdown - And the user clicks on the "Create Contract" button - Then the contract is created successfully - And the user is redirected to the Contract Management page - -@ContractManagement @EstateRole -Scenario: Estate user sees validation error when creating contract without required fields - Given the user is authenticated as an "Estate" user - When the user navigates to the Create New Contract page - And the user clicks on the "Create Contract" button - Then validation errors are displayed - And the "Description is required" error is shown - And the "Operator is required" error is shown - -@ContractManagement @EstateRole -Scenario: Estate user can navigate to edit contract page - Given the user is authenticated as an "Estate" user - When the user navigates to the Contract Management page - And the user clicks on the "Edit" button for the first contract - Then the Edit Contract page is displayed - And the contract description field contains "Standard Transaction Contract" - And the operator name is displayed as "Safaricom" - -@ContractManagement @EstateRole -Scenario: Estate user can view products on edit page - Given the user is authenticated as an "Estate" user - When the user navigates to the Contract Management page - And the user clicks on the "Edit" button for the first contract - Then the Edit Contract page is displayed - And the products section is displayed - And "2" products are listed - And the "Add Product" button is visible - -@ContractManagement @EstateRole -Scenario: Estate user can add a product to contract - Given the user is authenticated as an "Estate" user - When the user navigates to the Edit Contract page for the first contract - And the user clicks on the "Add Product" button - Then the Add Product modal is displayed - When the user enters "New Product" in the product name field - And the user enters "New Product Display" in the display text field - And the user enters "100" in the value field - And the user clicks on the "Add Product" button in the modal - Then the product is added successfully - And the Add Product modal is closed - -@ContractManagement @EstateRole -Scenario: Estate user can add a variable value product to contract - Given the user is authenticated as an "Estate" user - When the user navigates to the Edit Contract page for the first contract - And the user clicks on the "Add Product" button - Then the Add Product modal is displayed - When the user enters "Variable Product" in the product name field - And the user enters "Variable Display" in the display text field - And the user checks the "Variable Value" checkbox - And the user clicks on the "Add Product" button in the modal - Then the product is added successfully - -@ContractManagement @EstateRole -Scenario: Estate user can add a transaction fee to a product - Given the user is authenticated as an "Estate" user - When the user navigates to the Edit Contract page for the first contract - And the user clicks on the "Add Fee" button for the first product - Then the Add Transaction Fee modal is displayed - When the user enters "Test Fee" in the fee description field - And the user selects "Fixed" from the calculation type dropdown - And the user selects "Merchant" from the fee type dropdown - And the user enters "5.00" in the fee value field - And the user clicks on the "Add Fee" button in the modal - Then the transaction fee is added successfully - And the Add Transaction Fee modal is closed - -@ContractManagement @ViewerRole -Scenario: Viewer user can see Contract Management menu - Given the user is authenticated as a "Viewer" user - When the user navigates to the home page - Then the Contract Management menu item is visible - -@ContractManagement @ViewerRole -Scenario: Viewer user can view contracts list - Given the user is authenticated as a "Viewer" user - When the user navigates to the Contract Management page - Then the Contract Management page is displayed - And the page title is "Contract Management" - And "2" contracts are displayed in the list - And the "Add New Contract" button is not visible - -@ContractManagement @ViewerRole -Scenario: Viewer user can view contract details - Given the user is authenticated as a "Viewer" user - When the user navigates to the Contract Management page - And the user clicks on the "View" button for the first contract - Then the View Contract page is displayed - And the contract description is "Standard Transaction Contract" - And the contract operator is "Safaricom" - And the contract has "2" products - -@ContractManagement @ViewerRole -Scenario: Viewer user cannot access create new contract page - Given the user is authenticated as a "Viewer" user - When the user navigates to the Create New Contract page directly - Then an access denied message is displayed for contract creation - -@ContractManagement @ViewerRole -Scenario: Viewer user cannot see Edit button for contracts - Given the user is authenticated as a "Viewer" user - When the user navigates to the Contract Management page - Then the Contract Management page is displayed - And the "Edit" button is not visible for contracts - -@ContractManagement @ViewerRole -Scenario: Viewer user cannot access edit contract page directly - Given the user is authenticated as a "Viewer" user - When the user navigates to the Edit Contract page directly - Then an access denied message is displayed for contract editing diff --git a/EstateManagementUI.IntegrationTests/Features/Dashboard.feature b/EstateManagementUI.IntegrationTests/Features/Dashboard.feature index 5ba01ab3..575f9358 100644 --- a/EstateManagementUI.IntegrationTests/Features/Dashboard.feature +++ b/EstateManagementUI.IntegrationTests/Features/Dashboard.feature @@ -1,88 +1,88 @@ -Feature: Dashboard Integration Tests - As a user of the Estate Management UI - I want to see appropriate dashboard content based on my role - So that I can access the information relevant to my permissions +@base @background @dashboard +Feature: Dashboard + As an authenticated user + I want to view the dashboard + So that I can see the estate summary at a glance -Background: - Given the user navigates to the Dashboard + Background: + Given I create the following roles + | Role Name | + | Administrator | + | Estate | -@DashboardTests @AdminRole -Scenario: Administrator user sees limited dashboard view - Given the user is authenticated as an "Administrator" user - When the user navigates to the Dashboard - Then the Dashboard page is displayed - And the Administrator welcome message is displayed - And no merchant KPI cards are displayed - And no sales data cards are displayed + Given I create the following api scopes + | Name | DisplayName | Description | + | transactionProcessor | Transaction Processor REST Scope | Scope for Transaction Processor REST | + | fileProcessor | File Processor REST Scope | Scope for File Processor REST | + | estateReporting | Estate Reporting REST Scope | Scope for Estate Reporting REST | -@DashboardTests @EstateRole -Scenario: Estate user sees full dashboard with merchant KPIs - Given the user is authenticated as an "Estate" user - When the user navigates to the Dashboard - Then the Dashboard page is displayed - And the merchant KPI cards are displayed - And the Merchants with Sales in Last Hour shows "45" - And the Merchants with No Sales Today shows "12" - And the Merchants with No Sales in Last 7 Days shows "5" + Given I create the following api resources + | Name | DisplayName | Secret | Scopes | UserClaims | + | transactionProcessor | Transaction Processor REST | Secret1 | transactionProcessor | merchantId,estateId,role | + | fileProcessor | File Processor REST | Secret1 | fileProcessor | merchantId,estateId,role | + | estateReporting | Estate Reporting REST | Secret1 | estateReporting | merchantId,estateId,role | -@DashboardTests @EstateRole -Scenario: Estate user sees sales data on dashboard - Given the user is authenticated as an "Estate" user - When the user navigates to the Dashboard - Then the Dashboard page is displayed - And the Today's Sales card is displayed - And the Today's Sales card shows "523" transactions - And the Today's Sales card shows a value greater than $0 - And the Failed Sales card is displayed - And the Failed Sales card shows "15" transactions + Given I create the following identity resources + | Name | DisplayName | Description | UserClaims | + | openid | Your user identifier | | sub | + | profile | User profile | Your user profile information (first name, last name, etc.) | name,role,email,given_name,middle_name,family_name,estateId,merchantId | + | email | Email | Email and Email Verified Flags | email_verified,email | -@DashboardTests @EstateRole -Scenario: Estate user sees comparison date selector - Given the user is authenticated as an "Estate" user - When the user navigates to the Dashboard - Then the Dashboard page is displayed - And the comparison date selector is displayed + Given I create the following clients + | ClientId | Name | Secret | Scopes | GrantTypes | RedirectUris | PostLogoutRedirectUris | RequireConsent | AllowOfflineAccess | ClientUri | + | serviceClient | Service Client | Secret1 | transactionProcessor,fileProcessor,estateReporting | client_credentials | | | | | | + | estateUIClient | Merchant Client | Secret1 | fileProcessor,transactionProcessor,estateReporting,openid,email,profile | hybrid | https://localhost:[port]/signin-oidc | https://localhost:[port]/signout-oidc | false | true | https://[url]:[port] | -@DashboardTests @EstateRole -Scenario: Estate user sees recently created merchants - Given the user is authenticated as an "Estate" user - When the user navigates to the Dashboard - Then the Dashboard page is displayed - And the Recently Created Merchants section is displayed - And at least "1" merchant is shown in Recently Created Merchants + Given I create the following users + | Email Address | Phone Number | Given Name | Middle Name | Family Name | Claims | Roles | Password | + | administrator@admin.co.uk | 123456789 | Test | | User 1 | | Administrator | 123456 | -@DashboardTests @ViewerRole -Scenario: Viewer user sees full dashboard with merchant KPIs - Given the user is authenticated as a "Viewer" user - When the user navigates to the Dashboard - Then the Dashboard page is displayed - And the merchant KPI cards are displayed - And the Merchants with Sales in Last Hour shows "45" - And the Merchants with No Sales Today shows "12" - And the Merchants with No Sales in Last 7 Days shows "5" + Given I have a token to access the transaction Processor resource + | ClientId | + | serviceClient | -@DashboardTests @ViewerRole -Scenario: Viewer user sees sales data on dashboard - Given the user is authenticated as a "Viewer" user - When the user navigates to the Dashboard - Then the Dashboard page is displayed - And the Today's Sales card is displayed - And the Today's Sales card shows "523" transactions - And the Today's Sales card shows a value greater than $0 - And the Failed Sales card is displayed - And the Failed Sales card shows "15" transactions + Given I have created the following estates + | EstateName | + | Test Estate | -@DashboardTests @ViewerRole -Scenario: Viewer user sees comparison date selector - Given the user is authenticated as a "Viewer" user - When the user navigates to the Dashboard - Then the Dashboard page is displayed - And the comparison date selector is displayed + And I have created the following operators + | EstateName | OperatorName | RequireCustomMerchantNumber | RequireCustomTerminalNumber | + | Test Estate | Test Operator | True | True | -@DashboardTests @ViewerRole -Scenario: Viewer user sees recently created merchants - Given the user is authenticated as a "Viewer" user - When the user navigates to the Dashboard - Then the Dashboard page is displayed - And the Recently Created Merchants section is displayed - And at least "1" merchant is shown in Recently Created Merchants + And I have assigned the following operators to the estates + | EstateName | OperatorName | + | Test Estate | Test Operator | + + And I have created the following security users + | EmailAddress | Password | GivenName | FamilyName | EstateName | + | estateuser@testestate1.co.uk | 123456 | TestEstate | User1 | Test Estate | + + @Dashboard + Scenario: The home page is displayed + Given the user navigates to the app address + Then the home page is displayed + + @Dashboard @EstateRole + Scenario: Estate users can view the dashboard analytics + Given the user navigates to the app address + And I click on the Sign In Button + Then I am presented with a login screen + When I login with the username 'estateuser@testestate1.co.uk' and password '123456' + Then I should see the dashboard heading + And I should see the dashboard welcome message + And I should see the comparison date selector + And I should see the merchant KPI summary cards + And I should see the sales comparison cards + And I should not see the recent merchants section + + @Dashboard @AdministratorRole + Scenario: Administrators see the dashboard welcome panel + Given the user navigates to the app address + And I click on the Sign In Button + Then I am presented with a login screen + When I login with the username 'administrator@admin.co.uk' and password '123456' + Then I should see the dashboard heading + And I should see the administrator welcome panel + And I should not see the merchant KPI summary cards + And I should not see the sales comparison cards + And I should not see the recent merchants section diff --git a/EstateManagementUI.IntegrationTests/Features/EstateManagement.feature b/EstateManagementUI.IntegrationTests/Features/EstateManagement.feature deleted file mode 100644 index 68f4e2a2..00000000 --- a/EstateManagementUI.IntegrationTests/Features/EstateManagement.feature +++ /dev/null @@ -1,153 +0,0 @@ -Feature: Estate Management Integration Tests - As a user of the Estate Management UI - I want to access Estate Management functionality based on my role - So that I can view and manage estate information according to my permissions - -Background: - Given the user navigates to Estate Management - -@EstateManagementTests @AdminRole -Scenario: Administrator user cannot access Estate Management - Given the user is authenticated as an "Administrator" user - When the user navigates to Estate Management - Then the Estate Management menu is not visible - -@EstateManagementTests @EstateRole -Scenario: Estate user can view estate overview - Given the user is authenticated as an "Estate" user - When the user navigates to Estate Management - Then the Estate Management page is displayed - And the page title is "Estate Management" - And the estate name is "Test Estate" - And the estate reference is "Test Estate" - -@EstateManagementTests @EstateRole -Scenario: Estate user can view estate statistics - Given the user is authenticated as an "Estate" user - When the user navigates to Estate Management - Then the Estate Management page is displayed - And the Total Merchants count is "3" - And the Total Operators count is "2" - And the Total Contracts count is "2" - And the Total Users count is "5" - -@EstateManagementTests @EstateRole -Scenario: Estate user can view recent merchants section - Given the user is authenticated as an "Estate" user - When the user navigates to Estate Management - Then the Estate Management page is displayed - And the Recent Merchants section is displayed - And at least "1" merchant is shown in Recent Merchants - And the merchant "Test Merchant 1" with reference "MERCH001" is visible - -@EstateManagementTests @EstateRole -Scenario: Estate user can view contracts section - Given the user is authenticated as an "Estate" user - When the user navigates to Estate Management - Then the Estate Management page is displayed - And the Contracts section is displayed - And at least "1" contract is shown - And the contract "Standard Transaction Contract" for operator "Safaricom" is visible - -@EstateManagementTests @EstateRole -Scenario: Estate user can switch to operators tab - Given the user is authenticated as an "Estate" user - When the user navigates to Estate Management - And the user clicks on the "operators" tab - Then the operators tab content is displayed - And the Assigned Operators section is visible - And at least "2" operators are assigned - -@EstateManagementTests @EstateRole -Scenario: Estate user can view assigned operators - Given the user is authenticated as an "Estate" user - When the user navigates to Estate Management - And the user clicks on the "operators" tab - Then the operators tab content is displayed - And the operator "Safaricom" is listed - And the operator "Voucher" is listed - -@EstateManagementTests @EstateRole -Scenario: Estate user can see Add Operator button - Given the user is authenticated as an "Estate" user - When the user navigates to Estate Management - And the user clicks on the "operators" tab - Then the operators tab content is displayed - And the Add Operator button is visible - -@EstateManagementTests @EstateRole -Scenario: Estate user can remove an operator from the estate - Given the user is authenticated as an "Estate" user - When the user navigates to Estate Management - And the user clicks on the "operators" tab - And the user removes the operator "Voucher" - Then a success message is displayed - And the success message contains "Operator removed successfully" - And the operator "Voucher" is no longer listed - And the Total Operators count is "1" - -@EstateManagementTests @EstateRole -Scenario: Estate user can add an operator to the estate - Given the user is authenticated as an "Estate" user - When the user navigates to Estate Management - And the user clicks on the "operators" tab - And the user removes the operator "Voucher" - And the user clicks the Add Operator button - Then the operator selection form is displayed - When the user selects "Voucher" from the operator dropdown - And the user clicks the Add button - Then a success message is displayed - And the success message contains "Operator added successfully" - And the operator "Voucher" is listed - And the Total Operators count is "2" - -@EstateManagementTests @ViewerRole -Scenario: Viewer user can view estate overview - Given the user is authenticated as a "Viewer" user - When the user navigates to Estate Management - Then the Estate Management page is displayed - And the page title is "Estate Management" - And the estate name is "Test Estate" - And the estate reference is "Test Estate" - -@EstateManagementTests @ViewerRole -Scenario: Viewer user can view estate statistics - Given the user is authenticated as a "Viewer" user - When the user navigates to Estate Management - Then the Estate Management page is displayed - And the Total Merchants count is "3" - And the Total Operators count is "2" - And the Total Contracts count is "2" - And the Total Users count is "5" - -@EstateManagementTests @ViewerRole -Scenario: Viewer user can view recent merchants section - Given the user is authenticated as a "Viewer" user - When the user navigates to Estate Management - Then the Estate Management page is displayed - And the Recent Merchants section is displayed - And at least "1" merchant is shown in Recent Merchants - -@EstateManagementTests @ViewerRole -Scenario: Viewer user can view contracts section - Given the user is authenticated as a "Viewer" user - When the user navigates to Estate Management - Then the Estate Management page is displayed - And the Contracts section is displayed - And at least "1" contract is shown - -@EstateManagementTests @ViewerRole -Scenario: Viewer user can switch to operators tab - Given the user is authenticated as a "Viewer" user - When the user navigates to Estate Management - And the user clicks on the "operators" tab - Then the operators tab content is displayed - And the Assigned Operators section is visible - -@EstateManagementTests @ViewerRole -Scenario: Viewer user cannot see Add Operator button - Given the user is authenticated as a "Viewer" user - When the user navigates to Estate Management - And the user clicks on the "operators" tab - Then the operators tab content is displayed - And the Add Operator button is not visible diff --git a/EstateManagementUI.IntegrationTests/Features/MerchantManagement.feature b/EstateManagementUI.IntegrationTests/Features/MerchantManagement.feature deleted file mode 100644 index 870f3d46..00000000 --- a/EstateManagementUI.IntegrationTests/Features/MerchantManagement.feature +++ /dev/null @@ -1,367 +0,0 @@ -Feature: Merchant Management Integration Tests - As a user of the Estate Management UI - I want to access Merchant Management functionality based on my role - So that I can view and manage merchant information according to my permissions - -@MerchantManagementTests @AdminRole -Scenario: Administrator user cannot access Merchant Management - Given the user is authenticated as an "Administrator" user - When the user navigates to Merchant Management - Then the Merchant Management menu is not visible - -@MerchantManagementTests @EstateRole -Scenario: Estate user can view merchant list - Given the user is authenticated as an "Estate" user - When the user navigates to Merchant Management - Then the Merchant Management page is displayed - And the page title is "Merchant Management" - And the merchant list contains "3" merchants - -@MerchantManagementTests @EstateRole -Scenario: Estate user can view merchant list with correct data - Given the user is authenticated as an "Estate" user - When the user navigates to Merchant Management - Then the Merchant Management page is displayed - And the merchant "Test Merchant 1" with reference "MERCH001" is listed - And the merchant "Test Merchant 2" with reference "MERCH002" is listed - And the merchant "Test Merchant 3" with reference "MERCH003" is listed - -@MerchantManagementTests @EstateRole -Scenario: Estate user can view merchant balance information - Given the user is authenticated as an "Estate" user - When the user navigates to Merchant Management - Then the Merchant Management page is displayed - And the merchant "Test Merchant 1" shows balance "£10,000.00" - And the merchant "Test Merchant 1" shows available balance "£8,500.00" - And the merchant "Test Merchant 1" shows settlement schedule "Immediate" - -@MerchantManagementTests @EstateRole -Scenario: Estate user can see Add New Merchant button - Given the user is authenticated as an "Estate" user - When the user navigates to Merchant Management - Then the Merchant Management page is displayed - And the Add New Merchant button is visible - -@MerchantManagementTests @EstateRole -Scenario: Estate user can view a specific merchant - Given the user is authenticated as an "Estate" user - When the user navigates to Merchant Management - And the user clicks on merchant "Test Merchant 1" - Then the View Merchant page is displayed - And the merchant name is "Test Merchant 1" - And the merchant reference is "MERCH001" - -@MerchantManagementTests @EstateRole -Scenario: Estate user can view merchant details tab - Given the user is authenticated as an "Estate" user - When the user navigates to Merchant Management - And the user clicks on merchant "Test Merchant 1" - Then the View Merchant page is displayed - And the merchant balance is "£10,000.00" - And the merchant available balance is "£8,500.00" - And the merchant settlement schedule is "Immediate" - -@MerchantManagementTests @EstateRole -Scenario: Estate user can view merchant address details - Given the user is authenticated as an "Estate" user - When the user navigates to Merchant Management - And the user clicks on merchant "Test Merchant 1" - And the user clicks on the "address" tab - Then the address tab content is displayed - And the address line 1 is "123 Main Street" - And the town is "Test Town" - And the region is "Test Region" - And the postal code is "12345" - And the country is "Test Country" - -@MerchantManagementTests @EstateRole -Scenario: Estate user can view merchant contact details - Given the user is authenticated as an "Estate" user - When the user navigates to Merchant Management - And the user clicks on merchant "Test Merchant 1" - And the user clicks on the "contact" tab - Then the contact tab content is displayed - And the contact name is "John Smith" - And the contact email is "john@testmerchant.com" - And the contact phone is "555-1234" - -@MerchantManagementTests @EstateRole -Scenario: Estate user can view merchant assigned operators tab - Given the user is authenticated as an "Estate" user - When the user navigates to Merchant Management - And the user clicks on merchant "Test Merchant 1" - And the user clicks on the "operators" tab - Then the operators tab content is displayed - And the Assigned Operators section is visible - -@MerchantManagementTests @EstateRole -Scenario: Estate user can view merchant assigned contracts tab - Given the user is authenticated as an "Estate" user - When the user navigates to Merchant Management - And the user clicks on merchant "Test Merchant 1" - And the user clicks on the "contracts" tab - Then the contracts tab content is displayed - And the Assigned Contracts section is visible - -@MerchantManagementTests @EstateRole -Scenario: Estate user can view merchant assigned devices tab - Given the user is authenticated as an "Estate" user - When the user navigates to Merchant Management - And the user clicks on merchant "Test Merchant 1" - And the user clicks on the "devices" tab - Then the devices tab content is displayed - And the Assigned Devices section is visible - -@MerchantManagementTests @EstateRole -Scenario: Estate user can navigate to Create New Merchant page - Given the user is authenticated as an "Estate" user - When the user navigates to Merchant Management - And the user clicks the Add New Merchant button - Then the Create New Merchant page is displayed - And the merchant name field is visible - And the settlement schedule field is visible - And the address line 1 field is visible - And the contact name field is visible - -@MerchantManagementTests @EstateRole -Scenario: Estate user can navigate to Edit Merchant page - Given the user is authenticated as an "Estate" user - When the user navigates to Merchant Management - And the user clicks edit for merchant "Test Merchant 1" - Then the Edit Merchant page is displayed - And the merchant name field contains "Test Merchant 1" - -@MerchantManagementTests @EstateRole -Scenario: Estate user can see Make Deposit button - Given the user is authenticated as an "Estate" user - When the user navigates to Merchant Management - Then the Merchant Management page is displayed - And the Make Deposit button is visible for merchant "Test Merchant 1" - -@MerchantManagementTests @EstateRole -Scenario: Estate user can navigate to Make Deposit page - Given the user is authenticated as an "Estate" user - When the user navigates to Merchant Management - And the user clicks make deposit for merchant "Test Merchant 1" - Then the Make Deposit page is displayed - And the deposit amount field is visible - And the deposit date field is visible - And the deposit reference field is visible - -@MerchantManagementTests @ViewerRole -Scenario: Viewer user can view merchant list - Given the user is authenticated as a "Viewer" user - When the user navigates to Merchant Management - Then the Merchant Management page is displayed - And the page title is "Merchant Management" - And the merchant list contains "3" merchants - -@MerchantManagementTests @ViewerRole -Scenario: Viewer user can view merchant list with correct data - Given the user is authenticated as a "Viewer" user - When the user navigates to Merchant Management - Then the Merchant Management page is displayed - And the merchant "Test Merchant 1" with reference "MERCH001" is listed - And the merchant "Test Merchant 2" with reference "MERCH002" is listed - And the merchant "Test Merchant 3" with reference "MERCH003" is listed - -@MerchantManagementTests @ViewerRole -Scenario: Viewer user cannot see Add New Merchant button - Given the user is authenticated as a "Viewer" user - When the user navigates to Merchant Management - Then the Merchant Management page is displayed - And the Add New Merchant button is not visible - -@MerchantManagementTests @ViewerRole -Scenario: Viewer user can view a specific merchant - Given the user is authenticated as a "Viewer" user - When the user navigates to Merchant Management - And the user clicks on merchant "Test Merchant 1" - Then the View Merchant page is displayed - And the merchant name is "Test Merchant 1" - And the merchant reference is "MERCH001" - -@MerchantManagementTests @ViewerRole -Scenario: Viewer user can view merchant details tab - Given the user is authenticated as a "Viewer" user - When the user navigates to Merchant Management - And the user clicks on merchant "Test Merchant 1" - Then the View Merchant page is displayed - And the merchant balance is "£10,000.00" - And the merchant available balance is "£8,500.00" - -@MerchantManagementTests @ViewerRole -Scenario: Viewer user can view merchant address details - Given the user is authenticated as a "Viewer" user - When the user navigates to Merchant Management - And the user clicks on merchant "Test Merchant 1" - And the user clicks on the "address" tab - Then the address tab content is displayed - And the address line 1 is "123 Main Street" - -@MerchantManagementTests @ViewerRole -Scenario: Viewer user can view merchant contact details - Given the user is authenticated as a "Viewer" user - When the user navigates to Merchant Management - And the user clicks on merchant "Test Merchant 1" - And the user clicks on the "contact" tab - Then the contact tab content is displayed - And the contact name is "John Smith" - -@MerchantManagementTests @ViewerRole -Scenario: Viewer user cannot see Edit button - Given the user is authenticated as a "Viewer" user - When the user navigates to Merchant Management - Then the Merchant Management page is displayed - And the Edit button is not visible for merchant "Test Merchant 1" - -@MerchantManagementTests @ViewerRole -Scenario: Viewer user cannot see Make Deposit button - Given the user is authenticated as a "Viewer" user - When the user navigates to Merchant Management - Then the Merchant Management page is displayed - And the Make Deposit button is not visible for merchant "Test Merchant 1" - -@MerchantManagementTests @EstateRole @EditOperations -Scenario: Estate user can update merchant details - Given the user is authenticated as an "Estate" user - When the user navigates to Merchant Management - And the user clicks edit for merchant "Test Merchant 1" - Then the Edit Merchant page is displayed - When the user updates the merchant name to "Updated Merchant Name" - And the user updates the settlement schedule to "Weekly" - And the user clicks the Save Changes button - Then a success message is displayed - And the success message contains "Merchant details updated successfully" - -@MerchantManagementTests @EstateRole @EditOperations -Scenario: Estate user can update merchant address - Given the user is authenticated as an "Estate" user - When the user navigates to Merchant Management - And the user clicks edit for merchant "Test Merchant 1" - Then the Edit Merchant page is displayed - When the user clicks on the "address" tab - And the user updates the address line 1 to "456 Updated Street" - And the user updates the town to "New Town" - And the user updates the region to "New Region" - And the user clicks the Save Changes button - Then a success message is displayed - And the success message contains "Merchant address updated successfully" - -@MerchantManagementTests @EstateRole @EditOperations -Scenario: Estate user can update merchant contact details - Given the user is authenticated as an "Estate" user - When the user navigates to Merchant Management - And the user clicks edit for merchant "Test Merchant 1" - Then the Edit Merchant page is displayed - When the user clicks on the "contact" tab - And the user updates the contact name to "Jane Doe" - And the user updates the contact email to "jane@updated.com" - And the user updates the contact phone to "555-9999" - And the user clicks the Save Changes button - Then a success message is displayed - And the success message contains "Merchant contact updated successfully" - -@MerchantManagementTests @EstateRole @EditOperations -Scenario: Estate user can add an operator to a merchant - Given the user is authenticated as an "Estate" user - When the user navigates to Merchant Management - And the user clicks edit for merchant "Test Merchant 1" - Then the Edit Merchant page is displayed - When the user clicks on the "operators" tab - And the user clicks the Add Operator button - And the user selects "Safaricom" from the operator dropdown - And the user enters "12345" as the merchant number - And the user clicks the Add button in the operator form - Then a success message is displayed - And the success message contains "Operator added successfully" - And the operator "Safaricom" is listed in assigned operators - -@MerchantManagementTests @EstateRole @EditOperations -Scenario: Estate user can remove an operator from a merchant - Given the user is authenticated as an "Estate" user - When the user navigates to Merchant Management - And the user clicks edit for merchant "Test Merchant 1" - Then the Edit Merchant page is displayed - When the user clicks on the "operators" tab - And the user clicks the Add Operator button - And the user selects "Voucher" from the operator dropdown - And the user clicks the Add button in the operator form - Then a success message is displayed - When the user removes the operator "Voucher" - Then a success message is displayed - And the success message contains "Operator removed successfully" - And the operator "Voucher" is not listed in assigned operators - -@MerchantManagementTests @EstateRole @EditOperations -Scenario: Estate user can assign a contract to a merchant - Given the user is authenticated as an "Estate" user - When the user navigates to Merchant Management - And the user clicks edit for merchant "Test Merchant 1" - Then the Edit Merchant page is displayed - When the user clicks on the "contracts" tab - And the user clicks the Assign Contract button - And the user selects "Standard Transaction Contract" from the contract dropdown - And the user clicks the Assign button in the contract form - Then a success message is displayed - And the success message contains "Contract assigned successfully" - And the contract "Standard Transaction Contract" is listed in assigned contracts - -@MerchantManagementTests @EstateRole @EditOperations -Scenario: Estate user can remove a contract from a merchant - Given the user is authenticated as an "Estate" user - When the user navigates to Merchant Management - And the user clicks edit for merchant "Test Merchant 1" - Then the Edit Merchant page is displayed - When the user clicks on the "contracts" tab - And the user clicks the Assign Contract button - And the user selects "Voucher Sales Contract" from the contract dropdown - And the user clicks the Assign button in the contract form - Then a success message is displayed - When the user removes the contract "Voucher Sales Contract" - Then a success message is displayed - And the success message contains "Contract removed successfully" - And the contract "Voucher Sales Contract" is not listed in assigned contracts - -@MerchantManagementTests @EstateRole @EditOperations -Scenario: Estate user can add a device to a merchant - Given the user is authenticated as an "Estate" user - When the user navigates to Merchant Management - And the user clicks edit for merchant "Test Merchant 1" - Then the Edit Merchant page is displayed - When the user clicks on the "devices" tab - And the user clicks the Add Device button - And the user enters "DEVICE123" as the device identifier - And the user clicks the Add button in the device form - Then a success message is displayed - And the success message contains "Device added successfully" - And the device "DEVICE123" is listed in assigned devices - -@MerchantManagementTests @EstateRole @EditOperations -Scenario: Estate user can remove a device from a merchant - Given the user is authenticated as an "Estate" user - When the user navigates to Merchant Management - And the user clicks edit for merchant "Test Merchant 1" - Then the Edit Merchant page is displayed - When the user clicks on the "devices" tab - And the user clicks the Add Device button - And the user enters "DEVICE999" as the device identifier - And the user clicks the Add button in the device form - Then a success message is displayed - When the user removes the device "DEVICE999" - Then a success message is displayed - And the success message contains "Device removed successfully" - And the device "DEVICE999" is not listed in assigned devices - -@MerchantManagementTests @EstateRole @DepositOperations -Scenario: Estate user can make a deposit to a merchant - Given the user is authenticated as an "Estate" user - When the user navigates to Merchant Management - And the user clicks make deposit for merchant "Test Merchant 1" - Then the Make Deposit page is displayed - When the user enters "1000" as the deposit amount - And the user selects today as the deposit date - And the user enters "TEST-DEPOSIT-001" as the deposit reference - And the user clicks the Make Deposit button - Then a success message is displayed - And the success message contains "Deposit completed successfully" diff --git a/EstateManagementUI.IntegrationTests/Features/OperatorManagement.feature b/EstateManagementUI.IntegrationTests/Features/OperatorManagement.feature deleted file mode 100644 index b656df88..00000000 --- a/EstateManagementUI.IntegrationTests/Features/OperatorManagement.feature +++ /dev/null @@ -1,172 +0,0 @@ -Feature: Operator Management Integration Tests - As a user of the Estate Management UI - I want to access Operator Management functionality based on my role - So that I can view and manage operator information according to my permissions - -@OperatorManagementTests @AdminRole -Scenario: Administrator user cannot access Operator Management - Given the user is authenticated as an "Administrator" user - When the user navigates to Operator Management - Then the Operator Management menu is not visible - -@OperatorManagementTests @EstateRole -Scenario: Estate user can view operator list - Given the user is authenticated as an "Estate" user - When the user navigates to Operator Management - Then the Operator Management page is displayed - And the page title is "Operator Management" - And the operator list contains "2" operators - -@OperatorManagementTests @EstateRole -Scenario: Estate user can view operator list with correct data - Given the user is authenticated as an "Estate" user - When the user navigates to Operator Management - Then the Operator Management page is displayed - And the operator "Safaricom" is listed - And the operator "Voucher" is listed - -@OperatorManagementTests @EstateRole -Scenario: Estate user can view operator custom merchant number requirements - Given the user is authenticated as an "Estate" user - When the user navigates to Operator Management - Then the Operator Management page is displayed - And the operator "Safaricom" shows custom merchant number as "Required" - And the operator "Voucher" shows custom merchant number as "Not Required" - -@OperatorManagementTests @EstateRole -Scenario: Estate user can view operator custom terminal number requirements - Given the user is authenticated as an "Estate" user - When the user navigates to Operator Management - Then the Operator Management page is displayed - And the operator "Safaricom" shows custom terminal number as "Not Required" - And the operator "Voucher" shows custom terminal number as "Not Required" - -@OperatorManagementTests @EstateRole -Scenario: Estate user can see Add New Operator button - Given the user is authenticated as an "Estate" user - When the user navigates to Operator Management - Then the Operator Management page is displayed - And the Add New Operator button is visible - -@OperatorManagementTests @EstateRole -Scenario: Estate user can view a specific operator - Given the user is authenticated as an "Estate" user - When the user navigates to Operator Management - And the user clicks on operator "Safaricom" - Then the View Operator page is displayed - And the operator name is "Safaricom" - -@OperatorManagementTests @EstateRole -Scenario: Estate user can view operator requirement details - Given the user is authenticated as an "Estate" user - When the user navigates to Operator Management - And the user clicks on operator "Safaricom" - Then the View Operator page is displayed - And the operator custom merchant number requirement is "Required" - And the operator custom terminal number requirement is "Not Required" - -@OperatorManagementTests @EstateRole -Scenario: Estate user can navigate to Create New Operator page - Given the user is authenticated as an "Estate" user - When the user navigates to Operator Management - And the user clicks the Add New Operator button - Then the Create New Operator page is displayed - And the operator name field is visible - And the custom merchant number checkbox is visible - And the custom terminal number checkbox is visible - -@OperatorManagementTests @EstateRole -Scenario: Estate user can navigate to Edit Operator page from list - Given the user is authenticated as an "Estate" user - When the user navigates to Operator Management - And the user clicks edit for operator "Safaricom" - Then the Edit Operator page is displayed - And the operator name field contains "Safaricom" - -@OperatorManagementTests @ViewerRole -Scenario: Viewer user can view operator list - Given the user is authenticated as a "Viewer" user - When the user navigates to Operator Management - Then the Operator Management page is displayed - And the page title is "Operator Management" - And the operator list contains "2" operators - -@OperatorManagementTests @ViewerRole -Scenario: Viewer user can view operator list with correct data - Given the user is authenticated as a "Viewer" user - When the user navigates to Operator Management - Then the Operator Management page is displayed - And the operator "Safaricom" is listed - And the operator "Voucher" is listed - -@OperatorManagementTests @ViewerRole -Scenario: Viewer user cannot see Add New Operator button - Given the user is authenticated as a "Viewer" user - When the user navigates to Operator Management - Then the Operator Management page is displayed - And the Add New Operator button is not visible - -@OperatorManagementTests @ViewerRole -Scenario: Viewer user can view a specific operator - Given the user is authenticated as a "Viewer" user - When the user navigates to Operator Management - And the user clicks on operator "Safaricom" - Then the View Operator page is displayed - And the operator name is "Safaricom" - -@OperatorManagementTests @ViewerRole -Scenario: Viewer user can view operator requirement details - Given the user is authenticated as a "Viewer" user - When the user navigates to Operator Management - And the user clicks on operator "Safaricom" - Then the View Operator page is displayed - And the operator custom merchant number requirement is "Required" - And the operator custom terminal number requirement is "Not Required" - -@OperatorManagementTests @ViewerRole -Scenario: Viewer user cannot see Edit button on list - Given the user is authenticated as a "Viewer" user - When the user navigates to Operator Management - Then the Operator Management page is displayed - And the Edit button is not visible for operator "Safaricom" - -@OperatorManagementTests @EstateRole @EditOperations -Scenario: Estate user can update operator details - Given the user is authenticated as an "Estate" user - When the user navigates to Operator Management - And the user clicks edit for operator "Safaricom" - Then the Edit Operator page is displayed - When the user updates the operator name to "Updated Operator Name" - And the user updates the custom merchant number requirement to checked - And the user updates the custom terminal number requirement to checked - And the user clicks the Save Changes button - Then a success message is displayed - And the success message contains "Operator updated successfully" - -@OperatorManagementTests @EstateRole @CreateOperations -Scenario: Estate user can create a new operator - Given the user is authenticated as an "Estate" user - When the user navigates to Operator Management - And the user clicks the Add New Operator button - Then the Create New Operator page is displayed - When the user enters "New Test Operator" as the operator name - And the user updates the custom merchant number requirement to checked - And the user clicks the Create Operator button - Then a success message is displayed or user is redirected to operator list - And the operator "New Test Operator" is listed - -@OperatorManagementTests @EstateRole @CreateOperations -Scenario: Estate user cannot create operator with empty name - Given the user is authenticated as an "Estate" user - When the user navigates to Operator Management - And the user clicks the Add New Operator button - Then the Create New Operator page is displayed - When the user clicks the Create Operator button - Then a validation error is displayed for operator name - -@OperatorManagementTests @ViewerRole @EditOperations -Scenario: Viewer user cannot access Edit Operator page directly - Given the user is authenticated as a "Viewer" user - When the user navigates directly to Edit Operator page for "Safaricom" - Then an access denied message is displayed - And the message indicates no permission to edit operators diff --git a/EstateManagementUI.IntegrationTests/Features/Reporting.feature b/EstateManagementUI.IntegrationTests/Features/Reporting.feature deleted file mode 100644 index 04ae65fe..00000000 --- a/EstateManagementUI.IntegrationTests/Features/Reporting.feature +++ /dev/null @@ -1,372 +0,0 @@ -Feature: Reporting Integration Tests - As a user of the Estate Management UI - I want to access reporting functionality based on my role - So that I can view and analyze transaction and settlement data - -Background: - Given the user navigates to the Reporting Dashboard - -@ReportingTests @AdminRole -Scenario: Administrator user can access the Reporting Dashboard - Given the user is authenticated as an "Administrator" user - When the user navigates to the Reporting Dashboard - Then the Reporting Dashboard page is displayed - And the page title is "Reporting Dashboard" - -@ReportingTests @EstateRole -Scenario: Estate user can access the Reporting Dashboard - Given the user is authenticated as an "Estate" user - When the user navigates to the Reporting Dashboard - Then the Reporting Dashboard page is displayed - And the page title is "Reporting Dashboard" - And the Transaction Reporting section is displayed - And the Settlement Reporting section is displayed - And the Reconciliation section is displayed - And the KPI Reporting section is displayed - -@ReportingTests @ViewerRole -Scenario: Viewer user can access the Reporting Dashboard - Given the user is authenticated as a "Viewer" user - When the user navigates to the Reporting Dashboard - Then the Reporting Dashboard page is displayed - And the page title is "Reporting Dashboard" - And the Transaction Reporting section is displayed - And the Settlement Reporting section is displayed - -# Transaction Detail Report Tests - -@ReportingTests @EstateRole @TransactionDetail -Scenario: Estate user can view Transaction Detail Report - Given the user is authenticated as an "Estate" user - When the user navigates to the Transaction Detail Report - Then the Transaction Detail Report page is displayed - And the page title is "Transaction Detail Report" - And the filters section is displayed - And the transaction details grid is displayed - -@ReportingTests @EstateRole @TransactionDetail -Scenario: Estate user can filter Transaction Detail Report by date range - Given the user is authenticated as an "Estate" user - When the user navigates to the Transaction Detail Report - And the user sets the start date to "7" days ago - And the user sets the end date to today - And the user clicks Apply Filters - Then the transaction details grid displays filtered results - And the Total Transactions KPI is greater than "0" - -@ReportingTests @EstateRole @TransactionDetail -Scenario: Estate user can filter Transaction Detail Report by merchant - Given the user is authenticated as an "Estate" user - When the user navigates to the Transaction Detail Report - And the user selects a merchant from the filter dropdown - And the user clicks Apply Filters - Then the transaction details grid displays results for the selected merchant - And all displayed transactions match the selected merchant - -@ReportingTests @EstateRole @TransactionDetail -Scenario: Estate user can filter Transaction Detail Report by operator - Given the user is authenticated as an "Estate" user - When the user navigates to the Transaction Detail Report - And the user selects an operator from the filter dropdown - And the user clicks Apply Filters - Then the transaction details grid displays results for the selected operator - And all displayed transactions match the selected operator - -@ReportingTests @EstateRole @TransactionDetail -Scenario: Estate user can filter Transaction Detail Report by product - Given the user is authenticated as an "Estate" user - When the user navigates to the Transaction Detail Report - And the user selects a product from the filter dropdown - And the user clicks Apply Filters - Then the transaction details grid displays results for the selected product - And all displayed transactions match the selected product - -@ReportingTests @EstateRole @TransactionDetail -Scenario: Estate user can sort Transaction Detail Report columns - Given the user is authenticated as an "Estate" user - When the user navigates to the Transaction Detail Report - And the user clicks on the "Merchant" column header - Then the transaction details grid is sorted by "Merchant" in ascending order - -@ReportingTests @EstateRole @TransactionDetail -Scenario: Estate user can paginate through Transaction Detail Report - Given the user is authenticated as an "Estate" user - When the user navigates to the Transaction Detail Report - And the transaction details grid has multiple pages - When the user clicks the Next Page button - Then the transaction details grid displays the next page of results - -@ReportingTests @EstateRole @TransactionDetail -Scenario: Estate user can clear filters on Transaction Detail Report - Given the user is authenticated as an "Estate" user - When the user navigates to the Transaction Detail Report - And the user selects a merchant from the filter dropdown - And the user clicks Apply Filters - And the user clicks Clear Filters - Then all filter selections are reset to default values - And the transaction details grid displays unfiltered results - -# Transaction Summary by Merchant Tests - -@ReportingTests @EstateRole @TransactionSummaryMerchant -Scenario: Estate user can view Transaction Summary by Merchant Report - Given the user is authenticated as an "Estate" user - When the user navigates to the Transaction Summary by Merchant Report - Then the Transaction Summary by Merchant page is displayed - And the page title is "Transaction Summary by Merchant" - And the merchant summary grid is displayed - -@ReportingTests @EstateRole @TransactionSummaryMerchant -Scenario: Estate user sees merchant summary KPIs - Given the user is authenticated as an "Estate" user - When the user navigates to the Transaction Summary by Merchant Report - Then the Total Merchants KPI is displayed - And the Total Transactions KPI is displayed - And the Total Value KPI is displayed - And the Average Transaction KPI is displayed - -@ReportingTests @EstateRole @TransactionSummaryMerchant -Scenario: Estate user can filter Transaction Summary by Merchant by date range - Given the user is authenticated as an "Estate" user - When the user navigates to the Transaction Summary by Merchant Report - And the user sets the start date to "30" days ago - And the user sets the end date to today - And the user clicks Apply Filters - Then the merchant summary grid displays filtered results - -@ReportingTests @EstateRole @TransactionSummaryMerchant -Scenario: Estate user can filter Transaction Summary by Merchant by merchant - Given the user is authenticated as an "Estate" user - When the user navigates to the Transaction Summary by Merchant Report - And the user selects a merchant from the filter dropdown - And the user clicks Apply Filters - Then the merchant summary grid displays results for the selected merchant - -@ReportingTests @EstateRole @TransactionSummaryMerchant -Scenario: Estate user can filter Transaction Summary by Merchant by operator - Given the user is authenticated as an "Estate" user - When the user navigates to the Transaction Summary by Merchant Report - And the user selects an operator from the filter dropdown - And the user clicks Apply Filters - Then the merchant summary grid displays results for the selected operator - -@ReportingTests @EstateRole @TransactionSummaryMerchant -Scenario: Estate user can drill down from Merchant Summary to Transaction Detail - Given the user is authenticated as an "Estate" user - When the user navigates to the Transaction Summary by Merchant Report - And the user clicks View Details for a merchant - Then the user is navigated to the Transaction Detail Report - And the merchant filter is pre-populated - -# Transaction Summary by Operator Tests - -@ReportingTests @EstateRole @TransactionSummaryOperator -Scenario: Estate user can view Transaction Summary by Operator Report - Given the user is authenticated as an "Estate" user - When the user navigates to the Transaction Summary by Operator Report - Then the Transaction Summary by Operator page is displayed - And the page title is "Transaction Summary by Operator" - And the operator summary grid is displayed - -@ReportingTests @EstateRole @TransactionSummaryOperator -Scenario: Estate user can filter Transaction Summary by Operator by date range - Given the user is authenticated as an "Estate" user - When the user navigates to the Transaction Summary by Operator Report - And the user sets the start date to "30" days ago - And the user sets the end date to today - And the user clicks Apply Filters - Then the operator summary grid displays filtered results - -@ReportingTests @EstateRole @TransactionSummaryOperator -Scenario: Estate user can filter Transaction Summary by Operator by operator - Given the user is authenticated as an "Estate" user - When the user navigates to the Transaction Summary by Operator Report - And the user selects an operator from the filter dropdown - And the user clicks Apply Filters - Then the operator summary grid displays results for the selected operator - -# Product Performance Report Tests - -@ReportingTests @EstateRole @ProductPerformance -Scenario: Estate user can view Product Performance Report - Given the user is authenticated as an "Estate" user - When the user navigates to the Product Performance Report - Then the Product Performance Report page is displayed - And the page title is "Product Performance Report" - And the product performance grid is displayed - -@ReportingTests @EstateRole @ProductPerformance -Scenario: Estate user sees product performance KPIs - Given the user is authenticated as an "Estate" user - When the user navigates to the Product Performance Report - Then the Total Products KPI is displayed - And the Total Transactions KPI is displayed - And the Total Value KPI is displayed - And the Average per Product KPI is displayed - -@ReportingTests @EstateRole @ProductPerformance -Scenario: Estate user can filter Product Performance Report by date range - Given the user is authenticated as an "Estate" user - When the user navigates to the Product Performance Report - And the user sets the start date to "30" days ago - And the user sets the end date to today - And the user clicks Refresh - Then the product performance grid displays filtered results - -@ReportingTests @EstateRole @ProductPerformance -Scenario: Estate user can toggle between grid and chart view - Given the user is authenticated as an "Estate" user - When the user navigates to the Product Performance Report - And the user clicks Chart View button - Then the product performance chart is displayed - When the user clicks Grid View button - Then the product performance grid is displayed - -# Settlement Summary Report Tests - -@ReportingTests @EstateRole @SettlementSummary -Scenario: Estate user can view Settlement Summary Report - Given the user is authenticated as an "Estate" user - When the user navigates to the Settlement Summary Report - Then the Settlement Summary Report page is displayed - And the page title is "Settlement Summary Report" - And the settlement summary grid is displayed - -@ReportingTests @EstateRole @SettlementSummary -Scenario: Estate user sees settlement summary KPIs - Given the user is authenticated as an "Estate" user - When the user navigates to the Settlement Summary Report - Then the Total Merchants KPI is displayed - And the Gross Value KPI is displayed - And the Total Fees KPI is displayed - And the Net Settlement Value KPI is displayed - -@ReportingTests @EstateRole @SettlementSummary -Scenario: Estate user can filter Settlement Summary Report by date range - Given the user is authenticated as an "Estate" user - When the user navigates to the Settlement Summary Report - And the user sets the start date to "30" days ago - And the user sets the end date to today - And the user clicks Apply Filters - Then the settlement summary grid displays filtered results - -@ReportingTests @EstateRole @SettlementSummary -Scenario: Estate user can filter Settlement Summary Report by merchant - Given the user is authenticated as an "Estate" user - When the user navigates to the Settlement Summary Report - And the user selects a merchant from the filter dropdown - And the user clicks Apply Filters - Then the settlement summary grid displays results for the selected merchant - -@ReportingTests @EstateRole @SettlementSummary -Scenario: Estate user can filter Settlement Summary Report by settlement status - Given the user is authenticated as an "Estate" user - When the user navigates to the Settlement Summary Report - And the user selects "settled" from the status filter dropdown - And the user clicks Apply Filters - Then the settlement summary grid displays only settled settlements - -# Settlement Reconciliation Report Tests - -@ReportingTests @EstateRole @SettlementReconciliation -Scenario: Estate user can view Settlement Reconciliation Report - Given the user is authenticated as an "Estate" user - When the user navigates to the Settlement Reconciliation Report - Then the Settlement Reconciliation Report page is displayed - And the page title is "Settlement vs Transaction Reconciliation Report" - And the reconciliation grid is displayed - -@ReportingTests @EstateRole @SettlementReconciliation -Scenario: Estate user can filter Settlement Reconciliation Report by date range - Given the user is authenticated as an "Estate" user - When the user navigates to the Settlement Reconciliation Report - And the user sets the start date to "30" days ago - And the user sets the end date to today - And the user clicks Apply Filters - Then the reconciliation grid displays filtered results - -@ReportingTests @EstateRole @SettlementReconciliation -Scenario: Estate user can filter Settlement Reconciliation Report by merchant - Given the user is authenticated as an "Estate" user - When the user navigates to the Settlement Reconciliation Report - And the user selects a merchant from the filter dropdown - And the user clicks Apply Filters - Then the reconciliation grid displays results for the selected merchant - -# Merchant Settlement History Tests - -@ReportingTests @EstateRole @MerchantSettlementHistory -Scenario: Estate user can view Merchant Settlement History Report - Given the user is authenticated as an "Estate" user - When the user navigates to the Merchant Settlement History Report - Then the Merchant Settlement History page is displayed - And the page title is "Merchant Settlement History" - And the settlement history grid is displayed - -@ReportingTests @EstateRole @MerchantSettlementHistory -Scenario: Estate user can filter Merchant Settlement History by date range - Given the user is authenticated as an "Estate" user - When the user navigates to the Merchant Settlement History Report - And the user sets the start date to "30" days ago - And the user sets the end date to today - And the user clicks Apply Filters - Then the settlement history grid displays filtered results - -@ReportingTests @EstateRole @MerchantSettlementHistory -Scenario: Estate user can filter Merchant Settlement History by merchant - Given the user is authenticated as an "Estate" user - When the user navigates to the Merchant Settlement History Report - And the user selects a merchant from the filter dropdown - And the user clicks Apply Filters - Then the settlement history grid displays results for the selected merchant - -# Analytical Charts Tests - -@ReportingTests @EstateRole @AnalyticalCharts -Scenario: Estate user can view Analytical Charts Report - Given the user is authenticated as an "Estate" user - When the user navigates to the Analytical Charts Report - Then the Analytical Charts page is displayed - And the page title is "Analytical Charts (Volume & Value)" - And the analytical charts are displayed - -@ReportingTests @EstateRole @AnalyticalCharts -Scenario: Estate user can filter Analytical Charts by date range - Given the user is authenticated as an "Estate" user - When the user navigates to the Analytical Charts Report - And the user sets the start date to "30" days ago - And the user sets the end date to today - And the user clicks Refresh - Then the analytical charts display filtered results - -@ReportingTests @EstateRole @AnalyticalCharts -Scenario: Estate user can toggle between volume and value charts - Given the user is authenticated as an "Estate" user - When the user navigates to the Analytical Charts Report - And the user selects the Volume chart type - Then the volume chart is displayed - When the user selects the Value chart type - Then the value chart is displayed - -# Viewer Role Tests - -@ReportingTests @ViewerRole @TransactionDetail -Scenario: Viewer user can view Transaction Detail Report - Given the user is authenticated as a "Viewer" user - When the user navigates to the Transaction Detail Report - Then the Transaction Detail Report page is displayed - And the transaction details grid is displayed - -@ReportingTests @ViewerRole @TransactionSummaryMerchant -Scenario: Viewer user can view Transaction Summary by Merchant Report - Given the user is authenticated as a "Viewer" user - When the user navigates to the Transaction Summary by Merchant Report - Then the Transaction Summary by Merchant page is displayed - And the merchant summary grid is displayed - -@ReportingTests @ViewerRole @SettlementSummary -Scenario: Viewer user can view Settlement Summary Report - Given the user is authenticated as a "Viewer" user - When the user navigates to the Settlement Summary Report - Then the Settlement Summary Report page is displayed - And the settlement summary grid is displayed diff --git a/EstateManagementUI.IntegrationTests/Hooks/BrowserHooks.cs b/EstateManagementUI.IntegrationTests/Hooks/BrowserHooks.cs index 732d5a08..bcc41d1b 100644 --- a/EstateManagementUI.IntegrationTests/Hooks/BrowserHooks.cs +++ b/EstateManagementUI.IntegrationTests/Hooks/BrowserHooks.cs @@ -1,5 +1,7 @@ using Microsoft.Playwright; using Reqnroll; +using System.Net; +using System.Net.Sockets; namespace EstateManagementUI.IntegrationTests.Hooks; @@ -11,6 +13,8 @@ public class BrowserHooks { private static IPlaywright? _playwright; private static IBrowser? _browser; + private static TcpListener? _securityServiceForwarder; + private static CancellationTokenSource? _forwarderCancellation; private readonly ScenarioContext _scenarioContext; public BrowserHooks(ScenarioContext scenarioContext) @@ -38,7 +42,7 @@ public static async Task BeforeTestRun() /// /// Create a new browser page for each scenario /// - [BeforeScenario(Order = 0)] + [BeforeScenario(Order = 1)] public async Task BeforeScenario() { var page = await CreateBrowserPage(); @@ -103,6 +107,19 @@ private async Task CreateBrowserPage() Environment.GetEnvironmentVariable("IsCI"), "true", StringComparison.InvariantCultureIgnoreCase); + var securityServiceHost = Environment.GetEnvironmentVariable("SecurityServiceContainerName"); + var securityServiceLocalPortText = Environment.GetEnvironmentVariable("SecurityServiceLocalPort"); + var securityServicePortText = Environment.GetEnvironmentVariable("SecurityServicePort"); + var hostResolverRules = string.IsNullOrWhiteSpace(securityServiceHost) + ? null + : $"MAP {securityServiceHost} 127.0.0.1"; + + if (int.TryParse(securityServiceLocalPortText, out var localPort) && + int.TryParse(securityServicePortText, out var targetPort) && + localPort != targetPort) + { + await EnsureSecurityServiceForwarderAsync(localPort, targetPort); + } if (_browser == null) { @@ -111,24 +128,38 @@ private async Task CreateBrowserPage() "Firefox" => await _playwright!.Firefox.LaunchAsync(new BrowserTypeLaunchOptions { Headless = isCI, - Args = new[] { "--ignore-certificate-errors" } + Args = hostResolverRules is null + ? new[] { "--ignore-certificate-errors" } + : new[] { "--ignore-certificate-errors", $"--host-resolver-rules={hostResolverRules}" } }), "WebKit" => await _playwright!.Webkit.LaunchAsync(new BrowserTypeLaunchOptions { Headless = isCI, - Args = new[] { "--ignore-certificate-errors" } + Args = hostResolverRules is null + ? new[] { "--ignore-certificate-errors" } + : new[] { "--ignore-certificate-errors", $"--host-resolver-rules={hostResolverRules}" } }), _ => await _playwright!.Chromium.LaunchAsync(new BrowserTypeLaunchOptions { Headless = isCI, - Args = new[] - { - "--ignore-certificate-errors", - "--no-sandbox", - "--disable-dev-shm-usage", - "--disable-gpu", - "--disable-extensions" - } + Args = hostResolverRules is null + ? new[] + { + "--ignore-certificate-errors", + "--no-sandbox", + "--disable-dev-shm-usage", + "--disable-gpu", + "--disable-extensions" + } + : new[] + { + "--ignore-certificate-errors", + "--no-sandbox", + "--disable-dev-shm-usage", + "--disable-gpu", + "--disable-extensions", + $"--host-resolver-rules={hostResolverRules}" + } }) }; } @@ -141,4 +172,53 @@ private async Task CreateBrowserPage() return await context.NewPageAsync(); } + + private static async Task EnsureSecurityServiceForwarderAsync(int localPort, int targetPort) + { + if (_securityServiceForwarder != null) + { + return; + } + + _forwarderCancellation ??= new CancellationTokenSource(); + _securityServiceForwarder = new TcpListener(IPAddress.Loopback, localPort); + _securityServiceForwarder.Start(); + + _ = Task.Run(async () => + { + while (!_forwarderCancellation.IsCancellationRequested) + { + TcpClient? inboundClient = null; + TcpClient? outboundClient = null; + + try + { + inboundClient = await _securityServiceForwarder.AcceptTcpClientAsync(_forwarderCancellation.Token); + outboundClient = new TcpClient(); + await outboundClient.ConnectAsync(IPAddress.Loopback, targetPort, _forwarderCancellation.Token); + + var inboundStream = inboundClient.GetStream(); + var outboundStream = outboundClient.GetStream(); + + var inboundToOutbound = inboundStream.CopyToAsync(outboundStream, _forwarderCancellation.Token); + var outboundToInbound = outboundStream.CopyToAsync(inboundStream, _forwarderCancellation.Token); + + await Task.WhenAny(Task.WhenAll(inboundToOutbound, outboundToInbound), Task.Delay(Timeout.Infinite, _forwarderCancellation.Token)); + } + catch (OperationCanceledException) + { + break; + } + catch + { + // Ignore connection churn; the browser may open and close several sockets during navigation. + } + finally + { + outboundClient?.Close(); + inboundClient?.Close(); + } + } + }); + } } diff --git a/EstateManagementUI.IntegrationTests/Steps/BackgroundSteps.cs b/EstateManagementUI.IntegrationTests/Steps/BackgroundSteps.cs new file mode 100644 index 00000000..acefacc0 --- /dev/null +++ b/EstateManagementUI.IntegrationTests/Steps/BackgroundSteps.cs @@ -0,0 +1,213 @@ +using EstateManagementUI.IntegrationTests.Common; +using Reqnroll; +using SecurityService.DataTransferObjects; +using SecurityService.IntegrationTesting.Helpers; +using Shared.IntegrationTesting; +using Shouldly; +using SimpleResults; +using System; +using System.Collections.Generic; +using System.Text; +using TransactionProcessor.DataTransferObjects.Requests.Estate; +using TransactionProcessor.DataTransferObjects.Requests.Operator; +using TransactionProcessor.DataTransferObjects.Responses.Estate; +using TransactionProcessor.IntegrationTesting.Helpers; +using ReqnrollTableHelper = Shared.IntegrationTesting.ReqnrollTableHelper; + +namespace EstateManagementUI.IntegrationTests.Steps +{ + [Binding] + [Scope(Tag = "background")] + public class BackgroundSteps + { + private readonly TestingContext TestingContext; + private readonly SecurityServiceSteps SecurityServiceSteps; + private readonly TransactionProcessorSteps TransactionProcessorSteps; + + public BackgroundSteps(TestingContext testingContext) { + this.TestingContext = testingContext; + this.SecurityServiceSteps = new SecurityServiceSteps(testingContext.DockerHelper.SecurityServiceClient); + this.TransactionProcessorSteps = new TransactionProcessorSteps(testingContext.DockerHelper.TransactionProcessorClient, + testingContext.DockerHelper.TestHostHttpClient, testingContext.DockerHelper.ProjectionManagementClient); + } + + [Given(@"I create the following roles")] + public async Task GivenICreateTheFollowingRoles(DataTable table) + { + List requests = table.Rows.ToCreateRoleRequests(); + List<(String, String)> responses = await this.SecurityServiceSteps.GivenICreateTheFollowingRoles(requests, CancellationToken.None); + + foreach ((String, String) response in responses) + { + this.TestingContext.Roles.Add(response.Item1, response.Item2); + } + } + + [Given(@"I create the following api resources")] + public async Task GivenICreateTheFollowingApiResources(DataTable table) + { + List requests = table.Rows.ToCreateApiResourceRequests(); + await this.SecurityServiceSteps.GivenTheFollowingApiResourcesExist(requests); + + foreach (CreateApiResourceRequest createApiResourceRequest in requests) + { + this.TestingContext.ApiResources.Add(createApiResourceRequest.Name); + } + } + + [Given(@"I create the following api scopes")] + public async Task GivenICreateTheFollowingApiScopes(DataTable table) + { + List requests = table.Rows.ToCreateApiScopeRequests(); + await this.SecurityServiceSteps.GivenICreateTheFollowingApiScopes(requests); + } + + [Given(@"I create the following clients")] + public async Task GivenICreateTheFollowingClients(DataTable table) { + var estateManagementUiPort = this.TestingContext.DockerHelper.GetHostPort(ContainerType.EstateManagementUI); + List requests = table.Rows.ToCreateClientRequests(this.TestingContext.DockerHelper.TestId, estateManagementUiPort); + List<(String clientId, String secret, List allowedGrantTypes)> clients = await this.SecurityServiceSteps.GivenTheFollowingClientsExist(requests); + foreach ((String clientId, String secret, List allowedGrantTypes) client in clients) + { + this.TestingContext.AddClientDetails(client.clientId, client.secret, client.allowedGrantTypes); + } + } + + [Given(@"I create the following identity resources")] + public async Task GivenICreateTheFollowingIdentityResources(DataTable table) + { + foreach (DataTableRow tableRow in table.Rows) + { + // Get the scopes + String userClaims = ReqnrollTableHelper.GetStringRowValue(tableRow, "UserClaims"); + + CreateIdentityResourceRequest createIdentityResourceRequest = new CreateIdentityResourceRequest + { + Name = ReqnrollTableHelper.GetStringRowValue(tableRow, "Name"), + Claims = String.IsNullOrEmpty(userClaims) ? null : userClaims.Split(",").ToList(), + Description = ReqnrollTableHelper.GetStringRowValue(tableRow, "Description"), + DisplayName = ReqnrollTableHelper.GetStringRowValue(tableRow, "DisplayName") + }; + + await this.CreateIdentityResource(createIdentityResourceRequest, CancellationToken.None).ConfigureAwait(false); + } + } + + [Given(@"I create the following users")] + public async Task GivenICreateTheFollowingUsers(DataTable table) + { + List requests = table.Rows.ToCreateUserRequests(); + + List<(String, String)> results = await this.SecurityServiceSteps.GivenICreateTheFollowingUsers(requests, CancellationToken.None); + + foreach ((String, String) response in results) + { + this.TestingContext.Users.Add(response.Item1, response.Item2); + } + } + + private async Task CreateIdentityResource(CreateIdentityResourceRequest createIdentityResourceRequest, + CancellationToken cancellationToken) + { + Result>? identityResourceList = await this.TestingContext.DockerHelper.SecurityServiceClient.GetIdentityResources(cancellationToken); + if (identityResourceList.IsFailed) + { + // TODO: Handle error properly, e.g., show a message to the user + } + if (identityResourceList.Data == null || identityResourceList.Data.Any() == false) + { + Result result = await this + .TestingContext.DockerHelper.SecurityServiceClient + .CreateIdentityResource(createIdentityResourceRequest, cancellationToken) + .ConfigureAwait(false); + result.IsSuccess.ShouldBeTrue(); + + this.TestingContext.IdentityResources.Add(createIdentityResourceRequest.Name); + } + else + { + if (identityResourceList.Data.Any(i => i.Name == createIdentityResourceRequest.Name)) + { + return; + } + + Result result = await this + .TestingContext.DockerHelper.SecurityServiceClient + .CreateIdentityResource(createIdentityResourceRequest, cancellationToken) + .ConfigureAwait(false); + result.IsSuccess.ShouldBeTrue(); + + result.IsSuccess.ShouldBeTrue(); + + this.TestingContext.IdentityResources.Add(createIdentityResourceRequest.Name); + } + } + + [Given(@"I have a token to access the transaction Processor resource")] + public async Task GivenIHaveATokenToAccessTheTransactionProcessorResource(DataTable table) + { + DataTableRow firstRow = table.Rows.First(); + String clientId = ReqnrollTableHelper.GetStringRowValue(firstRow, "ClientId").Replace("[id]", this.TestingContext.DockerHelper.TestId.ToString("N")); + ClientDetails clientDetails = this.TestingContext.GetClientDetails(clientId); + + this.TestingContext.AccessToken = await this.SecurityServiceSteps.GetClientToken(clientDetails.ClientId, clientDetails.ClientSecret, CancellationToken.None); + } + + [Given(@"I have created the following estates")] + public async Task GivenIHaveCreatedTheFollowingEstates(DataTable table) + { + List requests = table.Rows.ToCreateEstateRequests(); + + List verifiedEstates = await this.TransactionProcessorSteps.WhenICreateTheFollowingEstatesX(this.TestingContext.AccessToken, requests); + + foreach (EstateResponse verifiedEstate in verifiedEstates) + { + //await Retry.For(async () => + //{ + // String databaseName = $"EstateReportingReadModel{verifiedEstate.EstateId}"; + // var connString = Setup.GetLocalConnectionString(databaseName); + // connString = $"{connString};Encrypt=false"; + // var ctx = new EstateManagementContext(connString); + + // var estates = ctx.Estates.ToList(); + // estates.Count.ShouldBe(1); + + this.TestingContext.AddEstateDetails(verifiedEstate.EstateId, verifiedEstate.EstateName, verifiedEstate.EstateReference); + this.TestingContext.Logger.LogInformation($"Estate {verifiedEstate.EstateName} created with Id {verifiedEstate.EstateId}"); + //}); + } + } + + [Given(@"I have created the following operators")] + public async Task GivenIHaveCreatedTheFollowingOperators(DataTable table) + { + List<(EstateDetails estate, CreateOperatorRequest request)> requests = table.Rows.ToCreateOperatorRequests(this.TestingContext.Estates); + + List<(Guid, EstateOperatorResponse)> results = await this.TransactionProcessorSteps.WhenICreateTheFollowingOperators(this.TestingContext.AccessToken, requests); + + foreach ((Guid, EstateOperatorResponse) result in results) + { + this.TestingContext.Logger.LogInformation($"Operator {result.Item2.Name} created with Id {result.Item2.OperatorId} for Estate {result.Item1}"); + } + } + + [Given("I have assigned the following operators to the estates")] + public async Task GivenIHaveAssignedTheFollowingOperatorsToTheEstates(DataTable dataTable) + { + List<(EstateDetails estate, AssignOperatorRequest request)> requests = dataTable.Rows.ToAssignOperatorToEstateRequests(this.TestingContext.Estates); + + await this.TransactionProcessorSteps.GivenIHaveAssignedTheFollowingOperatorsToTheEstates(this.TestingContext.AccessToken, requests); + + // TODO Verify + } + + [When(@"I create the following security users")] + [Given("I have created the following security users")] + public async Task WhenICreateTheFollowingSecurityUsers(DataTable table) + { + List createUserRequests = table.Rows.ToCreateNewUserRequests(this.TestingContext.Estates); + await this.TransactionProcessorSteps.WhenICreateTheFollowingSecurityUsers(this.TestingContext.AccessToken, createUserRequests, this.TestingContext.Estates); + } + + } +} diff --git a/EstateManagementUI.IntegrationTests/Steps/ContractManagementSteps.cs b/EstateManagementUI.IntegrationTests/Steps/ContractManagementSteps.cs deleted file mode 100644 index 486da967..00000000 --- a/EstateManagementUI.IntegrationTests/Steps/ContractManagementSteps.cs +++ /dev/null @@ -1,449 +0,0 @@ -using Microsoft.Playwright; -using Reqnroll; -using EstateManagementUI.IntegrationTests.Common; - -namespace EstateManagementUI.IntegrationTests.Steps; - -/// -/// Step definitions for Contract Management integration tests -/// Links feature file scenarios to browser automation code -/// -[Binding] -public class ContractManagementSteps -{ - private readonly IPage _page; - private readonly ContractManagementPageHelper _contractHelper; - private readonly ScenarioContext _scenarioContext; - - public ContractManagementSteps(ScenarioContext scenarioContext) - { - _scenarioContext = scenarioContext; - _page = scenarioContext.ScenarioContainer.Resolve(); - - // Get base URL from environment variable or use default - var baseUrl = Environment.GetEnvironmentVariable("APP_URL") ?? "https://localhost:5001"; - _contractHelper = new ContractManagementPageHelper(_page, baseUrl); - } - - #region Navigation Steps - - [Given(@"the user navigates to the Contract Management page")] - [When(@"the user navigates to the Contract Management page")] - public async Task GivenTheUserNavigatesToTheContractManagementPage() - { - await _contractHelper.NavigateToContractManagement(); - } - - [When(@"the user navigates to the home page")] - public async Task WhenTheUserNavigatesToTheHomePage() - { - await _contractHelper.NavigateToHome(); - } - - [When(@"the user navigates to the Create New Contract page")] - [When(@"the user navigates to the Create New Contract page directly")] - [Given(@"the user navigates to the Create New Contract page")] - public async Task WhenTheUserNavigatesToTheCreateNewContractPage() - { - await _contractHelper.NavigateToCreateNewContract(); - } - - [When(@"the user navigates to the Edit Contract page directly")] - public async Task WhenTheUserNavigatesToTheEditContractPageDirectly() - { - await _contractHelper.NavigateToEditFirstContract(); - } - - [When(@"the user navigates to the Edit Contract page for the first contract")] - [Given(@"the user navigates to the Edit Contract page for the first contract")] - public async Task WhenTheUserNavigatesToTheEditContractPageForTheFirstContract() - { - await _contractHelper.NavigateToEditFirstContract(); - } - - #endregion - - #region Authentication/Role Steps - - [Given(@"the user is authenticated as an? ""(.*)"" user")] - public async Task GivenTheUserIsAuthenticatedAsAUser(string role) - { - // Store the role in scenario context for reference - _scenarioContext["UserRole"] = role; - - // Note: This step assumes the application will be started in test mode - // with the appropriate role already configured. The actual authentication - // setup will be handled when the application startup is implemented. - await Task.CompletedTask; - } - - #endregion - - #region Menu Visibility Steps - - [Then(@"the Contract Management menu item is not visible")] - public async Task ThenTheContractManagementMenuItemIsNotVisible() - { - await _contractHelper.VerifyContractManagementMenuIsNotVisible(); - } - - [Then(@"the Contract Management menu item is visible")] - public async Task ThenTheContractManagementMenuItemIsVisible() - { - await _contractHelper.VerifyContractManagementMenuIsVisible(); - } - - #endregion - - #region Page Display Steps - - [Then(@"the Contract Management page is displayed")] - public async Task ThenTheContractManagementPageIsDisplayed() - { - await _contractHelper.VerifyContractManagementPageIsDisplayed(); - } - - [Then(@"the page title is ""(.*)""")] - public async Task ThenThePageTitleIs(string expectedTitle) - { - await _contractHelper.VerifyPageTitle(expectedTitle); - } - - [Then(@"an access denied message is displayed")] - public async Task ThenAnAccessDeniedMessageIsDisplayed() - { - await _contractHelper.VerifyAccessDeniedMessageIsDisplayed(); - } - - [Then(@"an access denied message is displayed for contract creation")] - public async Task ThenAnAccessDeniedMessageIsDisplayedForContractCreation() - { - await _contractHelper.VerifyAccessDeniedForContractCreation(); - } - - [Then(@"an access denied message is displayed for contract editing")] - public async Task ThenAnAccessDeniedMessageIsDisplayedForContractEditing() - { - await _contractHelper.VerifyAccessDeniedForContractEditing(); - } - - [Then(@"the View Contract page is displayed")] - public async Task ThenTheViewContractPageIsDisplayed() - { - await _contractHelper.VerifyViewContractPageIsDisplayed(); - } - - [Then(@"the Create New Contract page is displayed")] - public async Task ThenTheCreateNewContractPageIsDisplayed() - { - await _contractHelper.VerifyCreateNewContractPageIsDisplayed(); - } - - [Then(@"the Edit Contract page is displayed")] - public async Task ThenTheEditContractPageIsDisplayed() - { - await _contractHelper.VerifyEditContractPageIsDisplayed(); - } - - #endregion - - #region Contract List Verification Steps - - [Then(@"""(.*)"" contracts are displayed in the list")] - public async Task ThenContractsAreDisplayedInTheList(int count) - { - await _contractHelper.VerifyContractCount(count); - } - - [Then(@"the ""Add New Contract"" button is visible")] - public async Task ThenTheAddNewContractButtonIsVisible() - { - await _contractHelper.VerifyAddNewContractButtonIsVisible(); - } - - [Then(@"the ""Add New Contract"" button is not visible")] - public async Task ThenTheAddNewContractButtonIsNotVisible() - { - await _contractHelper.VerifyAddNewContractButtonIsNotVisible(); - } - - [Then(@"the ""Edit"" button is not visible for contracts")] - public async Task ThenTheEditButtonIsNotVisibleForContracts() - { - await _contractHelper.VerifyEditButtonIsNotVisibleForContracts(); - } - - #endregion - - #region Contract Details Verification Steps - - [Then(@"the contract description is ""(.*)""")] - public async Task ThenTheContractDescriptionIs(string description) - { - await _contractHelper.VerifyContractDescription(description); - } - - [Then(@"the contract operator is ""(.*)""")] - public async Task ThenTheContractOperatorIs(string operatorName) - { - await _contractHelper.VerifyContractOperator(operatorName); - } - - [Then(@"the contract has ""(.*)"" products")] - public async Task ThenTheContractHasProducts(int count) - { - await _contractHelper.VerifyContractProductCount(count); - } - - [Then(@"the first product is ""(.*)""")] - public async Task ThenTheFirstProductIs(string productName) - { - await _contractHelper.VerifyFirstProductName(productName); - } - - [Then(@"the first product has ""(.*)"" transaction fees")] - public async Task ThenTheFirstProductHasTransactionFees(int count) - { - await _contractHelper.VerifyFirstProductTransactionFeeCount(count); - } - - [Then(@"the product ""(.*)"" has a transaction fee ""(.*)"" with value ""(.*)""")] - public async Task ThenTheProductHasATransactionFeeWithValue(string productName, string feeDescription, string value) - { - await _contractHelper.VerifyProductTransactionFee(productName, feeDescription, value); - } - - #endregion - - #region Form Verification Steps - - [Then(@"the contract form is displayed")] - public async Task ThenTheContractFormIsDisplayed() - { - await _contractHelper.VerifyContractFormIsDisplayed(); - } - - [Then(@"the ""(.*)"" field is visible")] - public async Task ThenTheFieldIsVisible(string fieldLabel) - { - await _contractHelper.VerifyFieldIsVisible(fieldLabel); - } - - [Then(@"the ""(.*)"" dropdown is visible")] - public async Task ThenTheDropdownIsVisible(string fieldLabel) - { - await _contractHelper.VerifyFieldIsVisible(fieldLabel); - } - - [Then(@"the contract description field contains ""(.*)""")] - public async Task ThenTheContractDescriptionFieldContains(string value) - { - await _contractHelper.VerifyDescriptionFieldContains(value); - } - - [Then(@"the operator name is displayed as ""(.*)""")] - public async Task ThenTheOperatorNameIsDisplayedAs(string operatorName) - { - await _contractHelper.VerifyOperatorNameDisplayed(operatorName); - } - - [Then(@"the products section is displayed")] - public async Task ThenTheProductsSectionIsDisplayed() - { - await _contractHelper.VerifyProductsSectionIsDisplayed(); - } - - [Then(@"""(.*)"" products are listed")] - public async Task ThenProductsAreListed(int count) - { - await _contractHelper.VerifyProductCountOnEditPage(count); - } - - [Then(@"the ""Add Product"" button is visible")] - public async Task ThenTheAddProductButtonIsVisible() - { - await _contractHelper.VerifyAddProductButtonIsVisible(); - } - - [Then(@"validation errors are displayed")] - public async Task ThenValidationErrorsAreDisplayed() - { - await _contractHelper.VerifyValidationErrorsAreDisplayed(); - } - - [Then(@"the ""(.*)"" error is shown")] - public async Task ThenTheErrorIsShown(string errorMessage) - { - await _contractHelper.VerifyValidationErrorMessage(errorMessage); - } - - #endregion - - #region Interaction Steps - - [When(@"the user clicks on the ""View"" button for the first contract")] - public async Task WhenTheUserClicksOnTheViewButtonForTheFirstContract() - { - await _contractHelper.ClickViewButtonForFirstContract(); - } - - [When(@"the user clicks on the ""Edit"" button for the first contract")] - public async Task WhenTheUserClicksOnTheEditButtonForTheFirstContract() - { - await _contractHelper.ClickEditButtonForFirstContract(); - } - - [When(@"the user clicks on the ""Add New Contract"" button")] - public async Task WhenTheUserClicksOnTheAddNewContractButton() - { - await _contractHelper.ClickAddNewContractButton(); - } - - [When(@"the user enters ""(.*)"" in the ""Description"" field")] - public async Task WhenTheUserEntersInTheDescriptionField(string text) - { - await _contractHelper.EnterTextInField("Description", text); - } - - [When(@"the user selects ""(.*)"" from the ""Operator"" dropdown")] - public async Task WhenTheUserSelectsFromTheOperatorDropdown(string option) - { - await _contractHelper.SelectFromDropdown("Operator", option); - } - - [When(@"the user clicks on the ""Create Contract"" button")] - public async Task WhenTheUserClicksOnTheCreateContractButton() - { - await _contractHelper.ClickCreateContractButton(); - } - - [Then(@"the contract is created successfully")] - public async Task ThenTheContractIsCreatedSuccessfully() - { - await _contractHelper.VerifyContractCreatedSuccessfully(); - } - - [Then(@"the user is redirected to the Contract Management page")] - public async Task ThenTheUserIsRedirectedToTheContractManagementPage() - { - await _contractHelper.VerifyRedirectedToContractManagementPage(); - } - - #endregion - - #region Add Product Steps - - [When(@"the user clicks on the ""Add Product"" button")] - public async Task WhenTheUserClicksOnTheAddProductButton() - { - await _contractHelper.ClickAddProductButton(); - } - - [Then(@"the Add Product modal is displayed")] - public async Task ThenTheAddProductModalIsDisplayed() - { - await _contractHelper.VerifyAddProductModalIsDisplayed(); - } - - [When(@"the user enters ""(.*)"" in the product name field")] - public async Task WhenTheUserEntersInTheProductNameField(string productName) - { - await _contractHelper.EnterProductName(productName); - } - - [When(@"the user enters ""(.*)"" in the display text field")] - public async Task WhenTheUserEntersInTheDisplayTextField(string displayText) - { - await _contractHelper.EnterDisplayText(displayText); - } - - [When(@"the user enters ""(.*)"" in the value field")] - public async Task WhenTheUserEntersInTheValueField(string value) - { - await _contractHelper.EnterValue(value); - } - - [When(@"the user checks the ""Variable Value"" checkbox")] - public async Task WhenTheUserChecksTheVariableValueCheckbox() - { - await _contractHelper.CheckVariableValueCheckbox(); - } - - [When(@"the user clicks on the ""Add Product"" button in the modal")] - public async Task WhenTheUserClicksOnTheAddProductButtonInTheModal() - { - await _contractHelper.ClickAddProductButtonInModal(); - } - - [Then(@"the product is added successfully")] - public async Task ThenTheProductIsAddedSuccessfully() - { - await _contractHelper.VerifyProductAddedSuccessfully(); - } - - [Then(@"the Add Product modal is closed")] - public async Task ThenTheAddProductModalIsClosed() - { - await _contractHelper.VerifyAddProductModalIsClosed(); - } - - #endregion - - #region Add Transaction Fee Steps - - [When(@"the user clicks on the ""Add Fee"" button for the first product")] - public async Task WhenTheUserClicksOnTheAddFeeButtonForTheFirstProduct() - { - await _contractHelper.ClickAddFeeButtonForFirstProduct(); - } - - [Then(@"the Add Transaction Fee modal is displayed")] - public async Task ThenTheAddTransactionFeeModalIsDisplayed() - { - await _contractHelper.VerifyAddTransactionFeeModalIsDisplayed(); - } - - [When(@"the user enters ""(.*)"" in the fee description field")] - public async Task WhenTheUserEntersInTheFeeDescriptionField(string description) - { - await _contractHelper.EnterFeeDescription(description); - } - - [When(@"the user selects ""(.*)"" from the calculation type dropdown")] - public async Task WhenTheUserSelectsFromTheCalculationTypeDropdown(string calculationType) - { - await _contractHelper.SelectCalculationType(calculationType); - } - - [When(@"the user selects ""(.*)"" from the fee type dropdown")] - public async Task WhenTheUserSelectsFromTheFeeTypeDropdown(string feeType) - { - await _contractHelper.SelectFeeType(feeType); - } - - [When(@"the user enters ""(.*)"" in the fee value field")] - public async Task WhenTheUserEntersInTheFeeValueField(string value) - { - await _contractHelper.EnterFeeValue(value); - } - - [When(@"the user clicks on the ""Add Fee"" button in the modal")] - public async Task WhenTheUserClicksOnTheAddFeeButtonInTheModal() - { - await _contractHelper.ClickAddFeeButtonInModal(); - } - - [Then(@"the transaction fee is added successfully")] - public async Task ThenTheTransactionFeeIsAddedSuccessfully() - { - await _contractHelper.VerifyTransactionFeeAddedSuccessfully(); - } - - [Then(@"the Add Transaction Fee modal is closed")] - public async Task ThenTheAddTransactionFeeModalIsClosed() - { - await _contractHelper.VerifyAddTransactionFeeModalIsClosed(); - } - - #endregion -} diff --git a/EstateManagementUI.IntegrationTests/Steps/DashboardSteps.cs b/EstateManagementUI.IntegrationTests/Steps/DashboardSteps.cs index db148129..0181117d 100644 --- a/EstateManagementUI.IntegrationTests/Steps/DashboardSteps.cs +++ b/EstateManagementUI.IntegrationTests/Steps/DashboardSteps.cs @@ -1,187 +1,127 @@ +using EstateManagementUI.IntegrationTests.Common; using Microsoft.Playwright; using Reqnroll; -using EstateManagementUI.IntegrationTests.Common; namespace EstateManagementUI.IntegrationTests.Steps; -/// -/// Step definitions for Dashboard integration tests -/// Links feature file scenarios to browser automation code -/// [Binding] -public class DashboardSteps +[Scope(Tag = "dashboard")] +public sealed class DashboardSteps { private readonly IPage _page; - private readonly DashboardPageHelper _dashboardHelper; - private readonly ScenarioContext _scenarioContext; + private readonly TestingContext TestingContext; - public DashboardSteps(ScenarioContext scenarioContext) - { - _scenarioContext = scenarioContext; - _page = scenarioContext.ScenarioContainer.Resolve(); - - // Get base URL from environment variable or use default - var baseUrl = Environment.GetEnvironmentVariable("APP_URL") ?? "https://localhost:5001"; - _dashboardHelper = new DashboardPageHelper(_page, baseUrl); + public DashboardSteps(IPage page, TestingContext testingContext) { + _page = page; + this.TestingContext = testingContext; } - #region Navigation Steps - - [Given(@"the user navigates to the Dashboard")] - [When(@"the user navigates to the Dashboard")] - public async Task GivenTheUserNavigatesToTheDashboard() + [Given("the user navigates to the app address")] + [When("the user navigates to the app address")] + public async Task GivenTheUserNavigatesToTheAppAddress() { - await _dashboardHelper.NavigateToDashboard(); + await GetHelper().NavigateToAppAddressAsync(); } - #endregion - - #region Authentication/Role Steps - - [Given(@"the user is authenticated as an ""(.*)"" user")] - public async Task GivenTheUserIsAuthenticatedAsAUser(string role) + [Given("I click on the Sign In Button")] + public async Task WhenIClickOnTheSignInButton() { - // Store the role in scenario context for reference - _scenarioContext["UserRole"] = role; - - // Note: This step assumes the application will be started in test mode - // with the appropriate role already configured. The actual authentication - // setup will be handled when the application startup is implemented. - await Task.CompletedTask; + await GetHelper().ClickSignInButtonAsync(); } - #endregion - - #region Verification Steps - Common - - [Then(@"the Dashboard page is displayed")] - public async Task ThenTheDashboardPageIsDisplayed() + [Then("I am presented with a login screen")] + public async Task ThenIAmPresentedWithALoginScreen() { - await _dashboardHelper.VerifyDashboardPageTitle(); + await GetHelper().AssertLoginScreenVisibleAsync(); } - #endregion - - #region Verification Steps - Administrator Role - - [Then(@"the Administrator welcome message is displayed")] - public async Task ThenTheAdministratorWelcomeMessageIsDisplayed() + [When("I login with the username {string} and password {string}")] + public async Task WhenILoginWithTheUsernameAndPassword(string username, string password) { - await _dashboardHelper.VerifyAdministratorWelcomeMessage(); - } + //var loginPassword = password; - [Then(@"no merchant KPI cards are displayed")] - public async Task ThenNoMerchantKpiCardsAreDisplayed() - { - await _dashboardHelper.VerifyKpiCardsAreNotVisible(); - } + //if (this.TestingContext.Users.TryGetValue(username, out var seededPassword) && !string.IsNullOrWhiteSpace(seededPassword)) + //{ + // loginPassword = seededPassword; + //} - [Then(@"no sales data cards are displayed")] - public async Task ThenNoSalesDataCardsAreDisplayed() - { - await _dashboardHelper.VerifyComparisonDateSelectorIsNotVisible(); - await _dashboardHelper.VerifyRecentlyCreatedMerchantsIsNotVisible(); + await GetHelper().LoginAsync(username, password); } - #endregion - - #region Verification Steps - Estate/Viewer Roles - - [Then(@"the merchant KPI cards are displayed")] - public async Task ThenTheMerchantKpiCardsAreDisplayed() + [Then("I should see the dashboard heading")] + public async Task ThenIShouldSeeTheDashboardHeading() { - await _dashboardHelper.VerifyKpiCardsAreVisible(); + await GetHelper().AssertDashboardShellVisibleAsync(); } - [Then(@"the Merchants with Sales in Last Hour shows ""(.*)""")] - public async Task ThenTheMerchantsWithSalesInLastHourShows(int expectedValue) + [Then("the home page is displayed")] + public async Task ThenTheHomePageIsDisplayed() { - // This will be verified as part of the full KPI verification - _scenarioContext["ExpectedSalesLastHour"] = expectedValue; + await GetHelper().AssertHomePageVisibleAsync(); } - [Then(@"the Merchants with No Sales Today shows ""(.*)""")] - public async Task ThenTheMerchantsWithNoSalesTodayShows(int expectedValue) + [Then("I should see the dashboard welcome message")] + public async Task ThenIShouldSeeTheDashboardWelcomeMessage() { - _scenarioContext["ExpectedNoSalesToday"] = expectedValue; + await GetHelper().AssertDashboardWelcomeMessageVisibleAsync(); } - [Then(@"the Merchants with No Sales in Last 7 Days shows ""(.*)""")] - public async Task ThenTheMerchantsWithNoSalesInLast7DaysShows(int expectedValue) + [Then("I should see the comparison date selector")] + public async Task ThenIShouldSeeTheComparisonDateSelector() { - _scenarioContext["ExpectedNoSales7Days"] = expectedValue; - - // Now verify all KPI values - var salesLastHour = (int)_scenarioContext["ExpectedSalesLastHour"]; - var noSalesToday = (int)_scenarioContext["ExpectedNoSalesToday"]; - var noSales7Days = expectedValue; - - await _dashboardHelper.VerifyMerchantKpiValues(salesLastHour, noSalesToday, noSales7Days); + await GetHelper().AssertComparisonDateSelectorVisibleAsync(); } - [Then(@"the Today's Sales card is displayed")] - public async Task ThenTheTodaysSalesCardIsDisplayed() + [Then("I should see the merchant KPI summary cards")] + public async Task ThenIShouldSeeTheMerchantKpiSummaryCards() { - await _dashboardHelper.VerifyTodaysSalesCardIsDisplayed(); + await GetHelper().AssertMerchantKpiSummaryCardsVisibleAsync(); } - [Then(@"the Today's Sales card shows ""(.*)"" transactions")] - public async Task ThenTheTodaysSalesCardShowsTransactions(int transactionCount) + [Then("I should see the sales comparison cards")] + public async Task ThenIShouldSeeTheSalesComparisonCards() { - // Store for later verification - _scenarioContext["TodaysSalesCount"] = transactionCount; + await GetHelper().AssertSalesComparisonCardsVisibleAsync(); } - [Then(@"the Today's Sales card shows a value greater than \$(.*)")] - public async Task ThenTheTodaysSalesCardShowsAValueGreaterThan(decimal minimumValue) + [Then("I should see the recent merchants section")] + public async Task ThenIShouldSeeTheRecentMerchantsSection() { - // Verify sales values - var salesCount = (int)_scenarioContext["TodaysSalesCount"]; - await _dashboardHelper.VerifyTodaysSalesValues(salesCount, minimumValue); + await GetHelper().AssertRecentMerchantsSectionVisibleAsync(); } - [Then(@"the Failed Sales card is displayed")] - public async Task ThenTheFailedSalesCardIsDisplayed() + [Then("I should see the administrator welcome panel")] + public async Task ThenIShouldSeeTheAdministratorWelcomePanel() { - await _dashboardHelper.VerifyFailedSalesCardIsDisplayed(); + await GetHelper().AssertAdministratorDashboardVisibleAsync(); } - [Then(@"the Failed Sales card shows ""(.*)"" transactions")] - public async Task ThenTheFailedSalesCardShowsTransactions(int transactionCount) + [Then("I should not see the merchant KPI summary cards")] + public async Task ThenIShouldNotSeeTheMerchantKpiSummaryCards() { - await _dashboardHelper.VerifyFailedSalesValues(transactionCount); + await GetHelper().AssertMerchantKpiSummaryCardsNotVisibleAsync(); } - [Then(@"the comparison date selector is displayed")] - public async Task ThenTheComparisonDateSelectorIsDisplayed() + [Then("I should not see the sales comparison cards")] + public async Task ThenIShouldNotSeeTheSalesComparisonCards() { - await _dashboardHelper.VerifyComparisonDateSelectorIsVisible(); + await GetHelper().AssertSalesComparisonCardsNotVisibleAsync(); } - [Then(@"the Recently Created Merchants section is displayed")] - public async Task ThenTheRecentlyCreatedMerchantsSectionIsDisplayed() + [Then("I should not see the recent merchants section")] + public async Task ThenIShouldNotSeeTheRecentMerchantsSection() { - await _dashboardHelper.VerifyRecentlyCreatedMerchantsIsVisible(); + await GetHelper().AssertRecentMerchantsSectionNotVisibleAsync(); } - [Then(@"at least ""(.*)"" merchant is shown in Recently Created Merchants")] - public async Task ThenAtLeastMerchantIsShownInRecentlyCreatedMerchants(int minCount) + [Then("I should see the dashboard navigation link")] + public async Task ThenIShouldSeeTheDashboardNavigationLink() { - if (minCount > 0) - { - await _dashboardHelper.VerifyRecentlyCreatedMerchantsHasData(); - } + await GetHelper().AssertDashboardNavigationLinkVisibleAsync(); } - #endregion - - #region Interaction Steps - - [When(@"the user selects ""(.*)"" from the comparison date selector")] - public async Task WhenTheUserSelectsFromTheComparisonDateSelector(string dateOption) + private DashboardPageHelper GetHelper() { - await _dashboardHelper.SelectComparisonDate(dateOption); + return new DashboardPageHelper(_page, this.TestingContext); } - - #endregion } diff --git a/EstateManagementUI.IntegrationTests/Steps/EstateManagementSteps.cs b/EstateManagementUI.IntegrationTests/Steps/EstateManagementSteps.cs deleted file mode 100644 index 1a885576..00000000 --- a/EstateManagementUI.IntegrationTests/Steps/EstateManagementSteps.cs +++ /dev/null @@ -1,290 +0,0 @@ -using Microsoft.Playwright; -using Reqnroll; -using EstateManagementUI.IntegrationTests.Common; - -namespace EstateManagementUI.IntegrationTests.Steps; - -/// -/// Step definitions for Estate Management integration tests -/// Links feature file scenarios to browser automation code -/// -[Binding] -public class EstateManagementSteps -{ - private readonly IPage _page; - private readonly EstateManagementPageHelper _estateManagementHelper; - private readonly ScenarioContext _scenarioContext; - - public EstateManagementSteps(ScenarioContext scenarioContext) - { - _scenarioContext = scenarioContext; - _page = scenarioContext.ScenarioContainer.Resolve(); - - // Get base URL from environment variable or use default - var baseUrl = Environment.GetEnvironmentVariable("APP_URL") ?? "https://localhost:5001"; - _estateManagementHelper = new EstateManagementPageHelper(_page, baseUrl); - } - - #region Navigation Steps - - [Given(@"the user navigates to Estate Management")] - [When(@"the user navigates to Estate Management")] - public async Task GivenTheUserNavigatesToEstateManagement() - { - await _estateManagementHelper.NavigateToEstateManagement(); - } - - #endregion - - #region Authentication/Role Steps - - [Given(@"the user is authenticated as an ""(.*)"" user")] - public async Task GivenTheUserIsAuthenticatedAsAUser(string role) - { - // Store the role in scenario context for reference - _scenarioContext["UserRole"] = role; - - // Note: This step assumes the application will be started in test mode - // with the appropriate role already configured. The actual authentication - // setup will be handled when the application startup is implemented. - await Task.CompletedTask; - } - - [Given(@"the user is authenticated as a ""(.*)"" user")] - public async Task GivenTheUserIsAuthenticatedAsAViewerUser(string role) - { - // Store the role in scenario context for reference - _scenarioContext["UserRole"] = role; - - // Note: This step assumes the application will be started in test mode - // with the appropriate role already configured. The actual authentication - // setup will be handled when the application startup is implemented. - await Task.CompletedTask; - } - - #endregion - - #region Menu Visibility Steps - - [Then(@"the Estate Management menu is not visible")] - public async Task ThenTheEstateManagementMenuIsNotVisible() - { - // First navigate to home to check menu - await _estateManagementHelper.NavigateToHome(); - await _estateManagementHelper.VerifyEstateManagementMenuIsNotVisible(); - } - - [Then(@"the Estate Management menu is visible")] - public async Task ThenTheEstateManagementMenuIsVisible() - { - await _estateManagementHelper.VerifyEstateManagementMenuIsVisible(); - } - - #endregion - - #region Page Verification Steps - - [Then(@"the Estate Management page is displayed")] - public async Task ThenTheEstateManagementPageIsDisplayed() - { - await _estateManagementHelper.VerifyEstateManagementPageIsDisplayed(); - } - - [Then(@"the page title is ""(.*)""")] - public async Task ThenThePageTitleIs(string expectedTitle) - { - await _estateManagementHelper.VerifyPageTitle(expectedTitle); - } - - #endregion - - #region Estate Details Steps - - [Then(@"the estate name is ""(.*)""")] - public async Task ThenTheEstateNameIs(string expectedName) - { - await _estateManagementHelper.VerifyEstateName(expectedName); - } - - [Then(@"the estate reference is ""(.*)""")] - public async Task ThenTheEstateReferenceIs(string expectedReference) - { - await _estateManagementHelper.VerifyEstateReference(expectedReference); - } - - #endregion - - #region Statistics Steps - - [Then(@"the Total Merchants count is ""(.*)""")] - public async Task ThenTheTotalMerchantsCountIs(int expectedCount) - { - await _estateManagementHelper.VerifyTotalMerchantsCount(expectedCount); - } - - [Then(@"the Total Operators count is ""(.*)""")] - public async Task ThenTheTotalOperatorsCountIs(int expectedCount) - { - await _estateManagementHelper.VerifyTotalOperatorsCount(expectedCount); - } - - [Then(@"the Total Contracts count is ""(.*)""")] - public async Task ThenTheTotalContractsCountIs(int expectedCount) - { - await _estateManagementHelper.VerifyTotalContractsCount(expectedCount); - } - - [Then(@"the Total Users count is ""(.*)""")] - public async Task ThenTheTotalUsersCountIs(int expectedCount) - { - await _estateManagementHelper.VerifyTotalUsersCount(expectedCount); - } - - #endregion - - #region Recent Merchants Steps - - [Then(@"the Recent Merchants section is displayed")] - public async Task ThenTheRecentMerchantsSectionIsDisplayed() - { - await _estateManagementHelper.VerifyRecentMerchantsSection(); - } - - [Then(@"at least ""(.*)"" merchant is shown in Recent Merchants")] - public async Task ThenAtLeastMerchantIsShownInRecentMerchants(int minCount) - { - await _estateManagementHelper.VerifyRecentMerchantsCount(minCount); - } - - [Then(@"the merchant ""(.*)"" with reference ""(.*)"" is visible")] - public async Task ThenTheMerchantWithReferenceIsVisible(string merchantName, string merchantReference) - { - await _estateManagementHelper.VerifyMerchantIsVisible(merchantName, merchantReference); - } - - #endregion - - #region Contracts Steps - - [Then(@"the Contracts section is displayed")] - public async Task ThenTheContractsSectionIsDisplayed() - { - await _estateManagementHelper.VerifyContractsSection(); - } - - [Then(@"at least ""(.*)"" contract is shown")] - public async Task ThenAtLeastContractIsShown(int minCount) - { - await _estateManagementHelper.VerifyContractsCount(minCount); - } - - [Then(@"the contract ""(.*)"" for operator ""(.*)"" is visible")] - public async Task ThenTheContractForOperatorIsVisible(string contractDescription, string operatorName) - { - await _estateManagementHelper.VerifyContractIsVisible(contractDescription, operatorName); - } - - #endregion - - #region Tab Navigation Steps - - [When(@"the user clicks on the ""(.*)"" tab")] - public async Task WhenTheUserClicksOnTheTab(string tabName) - { - await _estateManagementHelper.ClickTab(tabName); - } - - [Then(@"the operators tab content is displayed")] - public async Task ThenTheOperatorsTabContentIsDisplayed() - { - await _estateManagementHelper.VerifyOperatorsTabContent(); - } - - #endregion - - #region Operators Tab Steps - - [Then(@"the Assigned Operators section is visible")] - public async Task ThenTheAssignedOperatorsSectionIsVisible() - { - await _estateManagementHelper.VerifyAssignedOperatorsSection(); - } - - [Then(@"at least ""(.*)"" operators are assigned")] - public async Task ThenAtLeastOperatorsAreAssigned(int minCount) - { - await _estateManagementHelper.VerifyAssignedOperatorsCount(minCount); - } - - [Then(@"the operator ""(.*)"" is listed")] - public async Task ThenTheOperatorIsListed(string operatorName) - { - await _estateManagementHelper.VerifyOperatorIsListed(operatorName); - } - - [Then(@"the Add Operator button is visible")] - public async Task ThenTheAddOperatorButtonIsVisible() - { - await _estateManagementHelper.VerifyAddOperatorButtonIsVisible(); - } - - [Then(@"the Add Operator button is not visible")] - public async Task ThenTheAddOperatorButtonIsNotVisible() - { - await _estateManagementHelper.VerifyAddOperatorButtonIsNotVisible(); - } - - #endregion - - #region Add/Remove Operator Steps - - [When(@"the user removes the operator ""(.*)""")] - public async Task WhenTheUserRemovesTheOperator(string operatorName) - { - await _estateManagementHelper.RemoveOperator(operatorName); - } - - [When(@"the user clicks the Add Operator button")] - public async Task WhenTheUserClicksTheAddOperatorButton() - { - await _estateManagementHelper.ClickAddOperatorButton(); - } - - [When(@"the user selects ""(.*)"" from the operator dropdown")] - public async Task WhenTheUserSelectsFromTheOperatorDropdown(string operatorName) - { - await _estateManagementHelper.SelectOperatorFromDropdown(operatorName); - } - - [When(@"the user clicks the Add button")] - public async Task WhenTheUserClicksTheAddButton() - { - await _estateManagementHelper.ClickAddButton(); - } - - [Then(@"a success message is displayed")] - public async Task ThenASuccessMessageIsDisplayed() - { - await _estateManagementHelper.VerifySuccessMessageIsDisplayed(); - } - - [Then(@"the success message contains ""(.*)""")] - public async Task ThenTheSuccessMessageContains(string expectedMessage) - { - await _estateManagementHelper.VerifySuccessMessageContains(expectedMessage); - } - - [Then(@"the operator ""(.*)"" is no longer listed")] - public async Task ThenTheOperatorIsNoLongerListed(string operatorName) - { - await _estateManagementHelper.VerifyOperatorIsNotListed(operatorName); - } - - [Then(@"the operator selection form is displayed")] - public async Task ThenTheOperatorSelectionFormIsDisplayed() - { - await _estateManagementHelper.VerifyOperatorSelectionFormIsDisplayed(); - } - - #endregion -} diff --git a/EstateManagementUI.IntegrationTests/Steps/MerchantManagementSteps.cs b/EstateManagementUI.IntegrationTests/Steps/MerchantManagementSteps.cs deleted file mode 100644 index 69502f4e..00000000 --- a/EstateManagementUI.IntegrationTests/Steps/MerchantManagementSteps.cs +++ /dev/null @@ -1,638 +0,0 @@ -using Microsoft.Playwright; -using Reqnroll; -using EstateManagementUI.IntegrationTests.Common; - -namespace EstateManagementUI.IntegrationTests.Steps; - -/// -/// Step definitions for Merchant Management integration tests -/// Links feature file scenarios to browser automation code -/// -[Binding] -public class MerchantManagementSteps -{ - private readonly IPage _page; - private readonly MerchantManagementPageHelper _merchantManagementHelper; - private readonly ScenarioContext _scenarioContext; - - public MerchantManagementSteps(ScenarioContext scenarioContext) - { - _scenarioContext = scenarioContext; - _page = scenarioContext.ScenarioContainer.Resolve(); - - // Get base URL from environment variable or use default - var baseUrl = Environment.GetEnvironmentVariable("APP_URL") ?? "https://localhost:5001"; - _merchantManagementHelper = new MerchantManagementPageHelper(_page, baseUrl); - } - - #region Navigation Steps - - [Given(@"the user navigates to Merchant Management")] - [When(@"the user navigates to Merchant Management")] - public async Task GivenTheUserNavigatesToMerchantManagement() - { - await _merchantManagementHelper.NavigateToMerchantManagement(); - } - - #endregion - - #region Authentication/Role Steps - - [Given(@"the user is authenticated as an? ""(.*)"" user")] - public async Task GivenTheUserIsAuthenticatedAsAUser(string role) - { - // Store the role in scenario context for reference - _scenarioContext["UserRole"] = role; - - // Note: This step assumes the application will be started in test mode - // with the appropriate role already configured. The actual authentication - // setup will be handled when the application startup is implemented. - await Task.CompletedTask; - } - - #endregion - - #region Menu Visibility Steps - - [Then(@"the Merchant Management menu is not visible")] - public async Task ThenTheMerchantManagementMenuIsNotVisible() - { - // First navigate to home to check menu - await _merchantManagementHelper.NavigateToHome(); - await _merchantManagementHelper.VerifyMerchantManagementMenuIsNotVisible(); - } - - [Then(@"the Merchant Management menu is visible")] - public async Task ThenTheMerchantManagementMenuIsVisible() - { - await _merchantManagementHelper.VerifyMerchantManagementMenuIsVisible(); - } - - #endregion - - #region Page Verification Steps - - [Then(@"the Merchant Management page is displayed")] - public async Task ThenTheMerchantManagementPageIsDisplayed() - { - await _merchantManagementHelper.VerifyMerchantManagementPageIsDisplayed(); - } - - [Then(@"the page title is ""(.*)""")] - public async Task ThenThePageTitleIs(string expectedTitle) - { - await _merchantManagementHelper.VerifyPageTitle(expectedTitle); - } - - [Then(@"the View Merchant page is displayed")] - public async Task ThenTheViewMerchantPageIsDisplayed() - { - await _merchantManagementHelper.VerifyViewMerchantPageIsDisplayed(); - } - - [Then(@"the Create New Merchant page is displayed")] - public async Task ThenTheCreateNewMerchantPageIsDisplayed() - { - await _merchantManagementHelper.VerifyCreateNewMerchantPageIsDisplayed(); - } - - [Then(@"the Edit Merchant page is displayed")] - public async Task ThenTheEditMerchantPageIsDisplayed() - { - await _merchantManagementHelper.VerifyEditMerchantPageIsDisplayed(); - } - - [Then(@"the Make Deposit page is displayed")] - public async Task ThenTheMakeDepositPageIsDisplayed() - { - await _merchantManagementHelper.VerifyMakeDepositPageIsDisplayed(); - } - - #endregion - - #region Merchant List Verification Steps - - [Then(@"the merchant list contains ""(.*)"" merchants")] - public async Task ThenTheMerchantListContainsMerchants(int expectedCount) - { - await _merchantManagementHelper.VerifyMerchantListCount(expectedCount); - } - - [Then(@"the merchant ""(.*)"" with reference ""(.*)"" is listed")] - public async Task ThenTheMerchantWithReferenceIsListed(string merchantName, string merchantReference) - { - await _merchantManagementHelper.VerifyMerchantIsListed(merchantName, merchantReference); - } - - [Then(@"the merchant ""(.*)"" shows balance ""(.*)""")] - public async Task ThenTheMerchantShowsBalance(string merchantName, string expectedBalance) - { - await _merchantManagementHelper.VerifyMerchantBalance(merchantName, expectedBalance); - } - - [Then(@"the merchant ""(.*)"" shows available balance ""(.*)""")] - public async Task ThenTheMerchantShowsAvailableBalance(string merchantName, string expectedAvailableBalance) - { - await _merchantManagementHelper.VerifyMerchantAvailableBalance(merchantName, expectedAvailableBalance); - } - - [Then(@"the merchant ""(.*)"" shows settlement schedule ""(.*)""")] - public async Task ThenTheMerchantShowsSettlementSchedule(string merchantName, string expectedSchedule) - { - await _merchantManagementHelper.VerifyMerchantSettlementSchedule(merchantName, expectedSchedule); - } - - #endregion - - #region Button Visibility Steps - - [Then(@"the Add New Merchant button is visible")] - public async Task ThenTheAddNewMerchantButtonIsVisible() - { - await _merchantManagementHelper.VerifyAddNewMerchantButtonIsVisible(); - } - - [Then(@"the Add New Merchant button is not visible")] - public async Task ThenTheAddNewMerchantButtonIsNotVisible() - { - await _merchantManagementHelper.VerifyAddNewMerchantButtonIsNotVisible(); - } - - [Then(@"the Edit button is visible for merchant ""(.*)""")] - public async Task ThenTheEditButtonIsVisibleForMerchant(string merchantName) - { - await _merchantManagementHelper.VerifyEditButtonIsVisibleForMerchant(merchantName); - } - - [Then(@"the Edit button is not visible for merchant ""(.*)""")] - public async Task ThenTheEditButtonIsNotVisibleForMerchant(string merchantName) - { - await _merchantManagementHelper.VerifyEditButtonIsNotVisibleForMerchant(merchantName); - } - - [Then(@"the Make Deposit button is visible for merchant ""(.*)""")] - public async Task ThenTheMakeDepositButtonIsVisibleForMerchant(string merchantName) - { - await _merchantManagementHelper.VerifyMakeDepositButtonIsVisibleForMerchant(merchantName); - } - - [Then(@"the Make Deposit button is not visible for merchant ""(.*)""")] - public async Task ThenTheMakeDepositButtonIsNotVisibleForMerchant(string merchantName) - { - await _merchantManagementHelper.VerifyMakeDepositButtonIsNotVisibleForMerchant(merchantName); - } - - #endregion - - #region Merchant Detail Verification Steps - - [Then(@"the merchant name is ""(.*)""")] - public async Task ThenTheMerchantNameIs(string expectedName) - { - await _merchantManagementHelper.VerifyMerchantName(expectedName); - } - - [Then(@"the merchant reference is ""(.*)""")] - public async Task ThenTheMerchantReferenceIs(string expectedReference) - { - await _merchantManagementHelper.VerifyMerchantReference(expectedReference); - } - - [Then(@"the merchant balance is ""(.*)""")] - public async Task ThenTheMerchantBalanceIs(string expectedBalance) - { - await _merchantManagementHelper.VerifyMerchantBalanceDetail(expectedBalance); - } - - [Then(@"the merchant available balance is ""(.*)""")] - public async Task ThenTheMerchantAvailableBalanceIs(string expectedAvailableBalance) - { - await _merchantManagementHelper.VerifyMerchantAvailableBalanceDetail(expectedAvailableBalance); - } - - [Then(@"the merchant settlement schedule is ""(.*)""")] - public async Task ThenTheMerchantSettlementScheduleIs(string expectedSchedule) - { - await _merchantManagementHelper.VerifyMerchantSettlementScheduleDetail(expectedSchedule); - } - - #endregion - - #region Tab Navigation Steps - - [When(@"the user clicks on the ""(.*)"" tab")] - public async Task WhenTheUserClicksOnTheTab(string tabName) - { - await _merchantManagementHelper.ClickTab(tabName); - } - - [Then(@"the address tab content is displayed")] - public async Task ThenTheAddressTabContentIsDisplayed() - { - await _merchantManagementHelper.VerifyAddressTabContent(); - } - - [Then(@"the contact tab content is displayed")] - public async Task ThenTheContactTabContentIsDisplayed() - { - await _merchantManagementHelper.VerifyContactTabContent(); - } - - [Then(@"the operators tab content is displayed")] - public async Task ThenTheOperatorsTabContentIsDisplayed() - { - await _merchantManagementHelper.VerifyOperatorsTabContent(); - } - - [Then(@"the Assigned Operators section is visible")] - public async Task ThenTheAssignedOperatorsSectionIsVisible() - { - await _merchantManagementHelper.VerifyAssignedOperatorsSection(); - } - - [Then(@"the contracts tab content is displayed")] - public async Task ThenTheContractsTabContentIsDisplayed() - { - await _merchantManagementHelper.VerifyContractsTabContent(); - } - - [Then(@"the Assigned Contracts section is visible")] - public async Task ThenTheAssignedContractsSectionIsVisible() - { - await _merchantManagementHelper.VerifyAssignedContractsSection(); - } - - [Then(@"the devices tab content is displayed")] - public async Task ThenTheDevicesTabContentIsDisplayed() - { - await _merchantManagementHelper.VerifyDevicesTabContent(); - } - - [Then(@"the Assigned Devices section is visible")] - public async Task ThenTheAssignedDevicesSectionIsVisible() - { - await _merchantManagementHelper.VerifyAssignedDevicesSection(); - } - - #endregion - - #region Address Details Steps - - [Then(@"the address line 1 is ""(.*)""")] - public async Task ThenTheAddressLine1Is(string expectedAddress) - { - await _merchantManagementHelper.VerifyAddressLine1(expectedAddress); - } - - [Then(@"the town is ""(.*)""")] - public async Task ThenTheTownIs(string expectedTown) - { - await _merchantManagementHelper.VerifyTown(expectedTown); - } - - [Then(@"the region is ""(.*)""")] - public async Task ThenTheRegionIs(string expectedRegion) - { - await _merchantManagementHelper.VerifyRegion(expectedRegion); - } - - [Then(@"the postal code is ""(.*)""")] - public async Task ThenThePostalCodeIs(string expectedPostalCode) - { - await _merchantManagementHelper.VerifyPostalCode(expectedPostalCode); - } - - [Then(@"the country is ""(.*)""")] - public async Task ThenTheCountryIs(string expectedCountry) - { - await _merchantManagementHelper.VerifyCountry(expectedCountry); - } - - #endregion - - #region Contact Details Steps - - [Then(@"the contact name is ""(.*)""")] - public async Task ThenTheContactNameIs(string expectedContactName) - { - await _merchantManagementHelper.VerifyContactName(expectedContactName); - } - - [Then(@"the contact email is ""(.*)""")] - public async Task ThenTheContactEmailIs(string expectedContactEmail) - { - await _merchantManagementHelper.VerifyContactEmail(expectedContactEmail); - } - - [Then(@"the contact phone is ""(.*)""")] - public async Task ThenTheContactPhoneIs(string expectedContactPhone) - { - await _merchantManagementHelper.VerifyContactPhone(expectedContactPhone); - } - - #endregion - - #region Form Field Verification Steps - - [Then(@"the merchant name field is visible")] - public async Task ThenTheMerchantNameFieldIsVisible() - { - await _merchantManagementHelper.VerifyMerchantNameFieldIsVisible(); - } - - [Then(@"the merchant name field contains ""(.*)""")] - public async Task ThenTheMerchantNameFieldContains(string expectedValue) - { - await _merchantManagementHelper.VerifyMerchantNameFieldContains(expectedValue); - } - - [Then(@"the settlement schedule field is visible")] - public async Task ThenTheSettlementScheduleFieldIsVisible() - { - await _merchantManagementHelper.VerifySettlementScheduleFieldIsVisible(); - } - - [Then(@"the address line 1 field is visible")] - public async Task ThenTheAddressLine1FieldIsVisible() - { - await _merchantManagementHelper.VerifyAddressLine1FieldIsVisible(); - } - - [Then(@"the contact name field is visible")] - public async Task ThenTheContactNameFieldIsVisible() - { - await _merchantManagementHelper.VerifyContactNameFieldIsVisible(); - } - - [Then(@"the deposit amount field is visible")] - public async Task ThenTheDepositAmountFieldIsVisible() - { - await _merchantManagementHelper.VerifyDepositAmountFieldIsVisible(); - } - - [Then(@"the deposit date field is visible")] - public async Task ThenTheDepositDateFieldIsVisible() - { - await _merchantManagementHelper.VerifyDepositDateFieldIsVisible(); - } - - [Then(@"the deposit reference field is visible")] - public async Task ThenTheDepositReferenceFieldIsVisible() - { - await _merchantManagementHelper.VerifyDepositReferenceFieldIsVisible(); - } - - #endregion - - #region Navigation Action Steps - - [When(@"the user clicks on merchant ""(.*)""")] - public async Task WhenTheUserClicksOnMerchant(string merchantName) - { - await _merchantManagementHelper.ClickOnMerchant(merchantName); - } - - [When(@"the user clicks the Add New Merchant button")] - public async Task WhenTheUserClicksTheAddNewMerchantButton() - { - await _merchantManagementHelper.ClickAddNewMerchantButton(); - } - - [When(@"the user clicks edit for merchant ""(.*)""")] - public async Task WhenTheUserClicksEditForMerchant(string merchantName) - { - await _merchantManagementHelper.ClickEditForMerchant(merchantName); - } - - [When(@"the user clicks make deposit for merchant ""(.*)""")] - public async Task WhenTheUserClicksMakeDepositForMerchant(string merchantName) - { - await _merchantManagementHelper.ClickMakeDepositForMerchant(merchantName); - } - - #endregion - - #region Edit Operations Steps - - [When(@"the user updates the merchant name to ""(.*)""")] - public async Task WhenTheUserUpdatesTheMerchantNameTo(string newName) - { - await _merchantManagementHelper.UpdateMerchantName(newName); - } - - [When(@"the user updates the settlement schedule to ""(.*)""")] - public async Task WhenTheUserUpdatesTheSettlementScheduleTo(string newSchedule) - { - await _merchantManagementHelper.UpdateSettlementSchedule(newSchedule); - } - - [When(@"the user clicks the Save Changes button")] - public async Task WhenTheUserClicksTheSaveChangesButton() - { - await _merchantManagementHelper.ClickSaveChangesButton(); - } - - [Then(@"a success message is displayed")] - public async Task ThenASuccessMessageIsDisplayed() - { - await _merchantManagementHelper.VerifySuccessMessageIsDisplayed(); - } - - [Then(@"the success message contains ""(.*)""")] - public async Task ThenTheSuccessMessageContains(string expectedMessage) - { - await _merchantManagementHelper.VerifySuccessMessageContains(expectedMessage); - } - - [When(@"the user updates the address line 1 to ""(.*)""")] - public async Task WhenTheUserUpdatesTheAddressLine1To(string newAddress) - { - await _merchantManagementHelper.UpdateAddressLine1(newAddress); - } - - [When(@"the user updates the town to ""(.*)""")] - public async Task WhenTheUserUpdatesTheTownTo(string newTown) - { - await _merchantManagementHelper.UpdateTown(newTown); - } - - [When(@"the user updates the region to ""(.*)""")] - public async Task WhenTheUserUpdatesTheRegionTo(string newRegion) - { - await _merchantManagementHelper.UpdateRegion(newRegion); - } - - [When(@"the user updates the contact name to ""(.*)""")] - public async Task WhenTheUserUpdatesTheContactNameTo(string newContactName) - { - await _merchantManagementHelper.UpdateContactName(newContactName); - } - - [When(@"the user updates the contact email to ""(.*)""")] - public async Task WhenTheUserUpdatesTheContactEmailTo(string newEmail) - { - await _merchantManagementHelper.UpdateContactEmail(newEmail); - } - - [When(@"the user updates the contact phone to ""(.*)""")] - public async Task WhenTheUserUpdatesTheContactPhoneTo(string newPhone) - { - await _merchantManagementHelper.UpdateContactPhone(newPhone); - } - - #endregion - - #region Operator Management Steps - - [When(@"the user clicks the Add Operator button")] - public async Task WhenTheUserClicksTheAddOperatorButton() - { - await _merchantManagementHelper.ClickAddOperatorButton(); - } - - [When(@"the user selects ""(.*)"" from the operator dropdown")] - public async Task WhenTheUserSelectsFromTheOperatorDropdown(string operatorName) - { - await _merchantManagementHelper.SelectOperatorFromDropdown(operatorName); - } - - [When(@"the user enters ""(.*)"" as the merchant number")] - public async Task WhenTheUserEntersAsTheMerchantNumber(string merchantNumber) - { - await _merchantManagementHelper.EnterMerchantNumber(merchantNumber); - } - - [When(@"the user clicks the Add button in the operator form")] - public async Task WhenTheUserClicksTheAddButtonInTheOperatorForm() - { - await _merchantManagementHelper.ClickAddButtonInOperatorForm(); - } - - [Then(@"the operator ""(.*)"" is listed in assigned operators")] - public async Task ThenTheOperatorIsListedInAssignedOperators(string operatorName) - { - await _merchantManagementHelper.VerifyOperatorIsListedInAssignedOperators(operatorName); - } - - [When(@"the user removes the operator ""(.*)""")] - public async Task WhenTheUserRemovesTheOperator(string operatorName) - { - await _merchantManagementHelper.RemoveOperatorFromMerchant(operatorName); - } - - [Then(@"the operator ""(.*)"" is not listed in assigned operators")] - public async Task ThenTheOperatorIsNotListedInAssignedOperators(string operatorName) - { - await _merchantManagementHelper.VerifyOperatorIsNotListedInAssignedOperators(operatorName); - } - - #endregion - - #region Contract Management Steps - - [When(@"the user clicks the Assign Contract button")] - public async Task WhenTheUserClicksTheAssignContractButton() - { - await _merchantManagementHelper.ClickAssignContractButton(); - } - - [When(@"the user selects ""(.*)"" from the contract dropdown")] - public async Task WhenTheUserSelectsFromTheContractDropdown(string contractDescription) - { - await _merchantManagementHelper.SelectContractFromDropdown(contractDescription); - } - - [When(@"the user clicks the Assign button in the contract form")] - public async Task WhenTheUserClicksTheAssignButtonInTheContractForm() - { - await _merchantManagementHelper.ClickAssignButtonInContractForm(); - } - - [Then(@"the contract ""(.*)"" is listed in assigned contracts")] - public async Task ThenTheContractIsListedInAssignedContracts(string contractDescription) - { - await _merchantManagementHelper.VerifyContractIsListedInAssignedContracts(contractDescription); - } - - [When(@"the user removes the contract ""(.*)""")] - public async Task WhenTheUserRemovesTheContract(string contractDescription) - { - await _merchantManagementHelper.RemoveContractFromMerchant(contractDescription); - } - - [Then(@"the contract ""(.*)"" is not listed in assigned contracts")] - public async Task ThenTheContractIsNotListedInAssignedContracts(string contractDescription) - { - await _merchantManagementHelper.VerifyContractIsNotListedInAssignedContracts(contractDescription); - } - - #endregion - - #region Device Management Steps - - [When(@"the user clicks the Add Device button")] - public async Task WhenTheUserClicksTheAddDeviceButton() - { - await _merchantManagementHelper.ClickAddDeviceButton(); - } - - [When(@"the user enters ""(.*)"" as the device identifier")] - public async Task WhenTheUserEntersAsTheDeviceIdentifier(string deviceIdentifier) - { - await _merchantManagementHelper.EnterDeviceIdentifier(deviceIdentifier); - } - - [When(@"the user clicks the Add button in the device form")] - public async Task WhenTheUserClicksTheAddButtonInTheDeviceForm() - { - await _merchantManagementHelper.ClickAddButtonInDeviceForm(); - } - - [Then(@"the device ""(.*)"" is listed in assigned devices")] - public async Task ThenTheDeviceIsListedInAssignedDevices(string deviceIdentifier) - { - await _merchantManagementHelper.VerifyDeviceIsListedInAssignedDevices(deviceIdentifier); - } - - [When(@"the user removes the device ""(.*)""")] - public async Task WhenTheUserRemovesTheDevice(string deviceIdentifier) - { - await _merchantManagementHelper.RemoveDeviceFromMerchant(deviceIdentifier); - } - - [Then(@"the device ""(.*)"" is not listed in assigned devices")] - public async Task ThenTheDeviceIsNotListedInAssignedDevices(string deviceIdentifier) - { - await _merchantManagementHelper.VerifyDeviceIsNotListedInAssignedDevices(deviceIdentifier); - } - - #endregion - - #region Deposit Steps - - [When(@"the user enters ""(.*)"" as the deposit amount")] - public async Task WhenTheUserEntersAsTheDepositAmount(string amount) - { - await _merchantManagementHelper.EnterDepositAmount(amount); - } - - [When(@"the user selects today as the deposit date")] - public async Task WhenTheUserSelectsTodayAsTheDepositDate() - { - await _merchantManagementHelper.SelectTodayAsDepositDate(); - } - - [When(@"the user enters ""(.*)"" as the deposit reference")] - public async Task WhenTheUserEntersAsTheDepositReference(string reference) - { - await _merchantManagementHelper.EnterDepositReference(reference); - } - - [When(@"the user clicks the Make Deposit button")] - public async Task WhenTheUserClicksTheMakeDepositButton() - { - await _merchantManagementHelper.ClickMakeDepositButton(); - } - - #endregion -} diff --git a/EstateManagementUI.IntegrationTests/Steps/OperatorManagementSteps.cs b/EstateManagementUI.IntegrationTests/Steps/OperatorManagementSteps.cs deleted file mode 100644 index 34e67a36..00000000 --- a/EstateManagementUI.IntegrationTests/Steps/OperatorManagementSteps.cs +++ /dev/null @@ -1,342 +0,0 @@ -using Microsoft.Playwright; -using Reqnroll; -using EstateManagementUI.IntegrationTests.Common; - -namespace EstateManagementUI.IntegrationTests.Steps; - -/// -/// Step definitions for Operator Management integration tests -/// Links feature file scenarios to browser automation code -/// -[Binding] -public class OperatorManagementSteps -{ - private readonly IPage _page; - private readonly OperatorManagementPageHelper _operatorManagementHelper; - private readonly ScenarioContext _scenarioContext; - - public OperatorManagementSteps(ScenarioContext scenarioContext) - { - _scenarioContext = scenarioContext; - _page = scenarioContext.ScenarioContainer.Resolve(); - - // Get base URL from environment variable or use default - var baseUrl = Environment.GetEnvironmentVariable("APP_URL") ?? "https://localhost:5001"; - _operatorManagementHelper = new OperatorManagementPageHelper(_page, baseUrl); - } - - #region Navigation Steps - - [Given(@"the user navigates to Operator Management")] - [When(@"the user navigates to Operator Management")] - public async Task GivenTheUserNavigatesToOperatorManagement() - { - await _operatorManagementHelper.NavigateToOperatorManagement(); - } - - [When(@"the user navigates directly to Edit Operator page for ""(.*)""")] - public async Task WhenTheUserNavigatesDirectlyToEditOperatorPageFor(string operatorName) - { - await _operatorManagementHelper.NavigateToEditOperatorPage(operatorName); - } - - #endregion - - #region Authentication/Role Steps - - [Given(@"the user is authenticated as an? ""(.*)"" user")] - public async Task GivenTheUserIsAuthenticatedAsAUser(string role) - { - // Store the role in scenario context for reference - _scenarioContext["UserRole"] = role; - - // Note: This step assumes the application will be started in test mode - // with the appropriate role already configured. The actual authentication - // setup will be handled when the application startup is implemented. - await Task.CompletedTask; - } - - #endregion - - #region Menu Visibility Steps - - [Then(@"the Operator Management menu is not visible")] - public async Task ThenTheOperatorManagementMenuIsNotVisible() - { - // First navigate to home to check menu - await _operatorManagementHelper.NavigateToHome(); - await _operatorManagementHelper.VerifyOperatorManagementMenuIsNotVisible(); - } - - [Then(@"the Operator Management menu is visible")] - public async Task ThenTheOperatorManagementMenuIsVisible() - { - await _operatorManagementHelper.VerifyOperatorManagementMenuIsVisible(); - } - - #endregion - - #region Page Verification Steps - - [Then(@"the Operator Management page is displayed")] - public async Task ThenTheOperatorManagementPageIsDisplayed() - { - await _operatorManagementHelper.VerifyOperatorManagementPageIsDisplayed(); - } - - [Then(@"the page title is ""(.*)""")] - public async Task ThenThePageTitleIs(string expectedTitle) - { - await _operatorManagementHelper.VerifyPageTitle(expectedTitle); - } - - [Then(@"the View Operator page is displayed")] - public async Task ThenTheViewOperatorPageIsDisplayed() - { - await _operatorManagementHelper.VerifyViewOperatorPageIsDisplayed(); - } - - [Then(@"the Create New Operator page is displayed")] - public async Task ThenTheCreateNewOperatorPageIsDisplayed() - { - await _operatorManagementHelper.VerifyCreateNewOperatorPageIsDisplayed(); - } - - [Then(@"the Edit Operator page is displayed")] - public async Task ThenTheEditOperatorPageIsDisplayed() - { - await _operatorManagementHelper.VerifyEditOperatorPageIsDisplayed(); - } - - [Then(@"an access denied message is displayed")] - public async Task ThenAnAccessDeniedMessageIsDisplayed() - { - await _operatorManagementHelper.VerifyAccessDeniedMessageIsDisplayed(); - } - - [Then(@"the message indicates no permission to edit operators")] - public async Task ThenTheMessageIndicatesNoPermissionToEditOperators() - { - await _operatorManagementHelper.VerifyAccessDeniedMessageForEditOperators(); - } - - #endregion - - #region Operator List Verification Steps - - [Then(@"the operator list contains ""(.*)"" operators")] - public async Task ThenTheOperatorListContainsOperators(int expectedCount) - { - await _operatorManagementHelper.VerifyOperatorListCount(expectedCount); - } - - [Then(@"the operator ""(.*)"" is listed")] - public async Task ThenTheOperatorIsListed(string operatorName) - { - await _operatorManagementHelper.VerifyOperatorIsListed(operatorName); - } - - [Then(@"the operator ""(.*)"" shows custom merchant number as ""(.*)""")] - public async Task ThenTheOperatorShowsCustomMerchantNumberAs(string operatorName, string expectedStatus) - { - await _operatorManagementHelper.VerifyOperatorCustomMerchantNumberRequirement(operatorName, expectedStatus); - } - - [Then(@"the operator ""(.*)"" shows custom terminal number as ""(.*)""")] - public async Task ThenTheOperatorShowsCustomTerminalNumberAs(string operatorName, string expectedStatus) - { - await _operatorManagementHelper.VerifyOperatorCustomTerminalNumberRequirement(operatorName, expectedStatus); - } - - #endregion - - #region Button Visibility Steps - - [Then(@"the Add New Operator button is visible")] - public async Task ThenTheAddNewOperatorButtonIsVisible() - { - await _operatorManagementHelper.VerifyAddNewOperatorButtonIsVisible(); - } - - [Then(@"the Add New Operator button is not visible")] - public async Task ThenTheAddNewOperatorButtonIsNotVisible() - { - await _operatorManagementHelper.VerifyAddNewOperatorButtonIsNotVisible(); - } - - [Then(@"the Edit Operator button is visible")] - public async Task ThenTheEditOperatorButtonIsVisible() - { - await _operatorManagementHelper.VerifyEditOperatorButtonIsVisible(); - } - - [Then(@"the Edit button is visible for operator ""(.*)""")] - public async Task ThenTheEditButtonIsVisibleForOperator(string operatorName) - { - await _operatorManagementHelper.VerifyEditButtonIsVisibleForOperator(operatorName); - } - - [Then(@"the Edit button is not visible for operator ""(.*)""")] - public async Task ThenTheEditButtonIsNotVisibleForOperator(string operatorName) - { - await _operatorManagementHelper.VerifyEditButtonIsNotVisibleForOperator(operatorName); - } - - #endregion - - #region Operator Detail Verification Steps - - [Then(@"the operator name is ""(.*)""")] - public async Task ThenTheOperatorNameIs(string expectedName) - { - await _operatorManagementHelper.VerifyOperatorName(expectedName); - } - - [Then(@"the operator custom merchant number requirement is ""(.*)""")] - public async Task ThenTheOperatorCustomMerchantNumberRequirementIs(string expectedStatus) - { - await _operatorManagementHelper.VerifyOperatorCustomMerchantNumberRequirementDetail(expectedStatus); - } - - [Then(@"the operator custom terminal number requirement is ""(.*)""")] - public async Task ThenTheOperatorCustomTerminalNumberRequirementIs(string expectedStatus) - { - await _operatorManagementHelper.VerifyOperatorCustomTerminalNumberRequirementDetail(expectedStatus); - } - - #endregion - - #region Form Field Verification Steps - - [Then(@"the operator name field is visible")] - public async Task ThenTheOperatorNameFieldIsVisible() - { - await _operatorManagementHelper.VerifyOperatorNameFieldIsVisible(); - } - - [Then(@"the operator name field contains ""(.*)""")] - public async Task ThenTheOperatorNameFieldContains(string expectedValue) - { - await _operatorManagementHelper.VerifyOperatorNameFieldContains(expectedValue); - } - - [Then(@"the custom merchant number checkbox is visible")] - public async Task ThenTheCustomMerchantNumberCheckboxIsVisible() - { - await _operatorManagementHelper.VerifyCustomMerchantNumberCheckboxIsVisible(); - } - - [Then(@"the custom terminal number checkbox is visible")] - public async Task ThenTheCustomTerminalNumberCheckboxIsVisible() - { - await _operatorManagementHelper.VerifyCustomTerminalNumberCheckboxIsVisible(); - } - - #endregion - - #region Navigation Action Steps - - [When(@"the user clicks on operator ""(.*)""")] - public async Task WhenTheUserClicksOnOperator(string operatorName) - { - await _operatorManagementHelper.ClickOnOperator(operatorName); - } - - [When(@"the user clicks the Add New Operator button")] - public async Task WhenTheUserClicksTheAddNewOperatorButton() - { - await _operatorManagementHelper.ClickAddNewOperatorButton(); - } - - [When(@"the user clicks edit for operator ""(.*)""")] - public async Task WhenTheUserClicksEditForOperator(string operatorName) - { - await _operatorManagementHelper.ClickEditForOperator(operatorName); - } - - [When(@"the user clicks the Edit Operator button")] - public async Task WhenTheUserClicksTheEditOperatorButton() - { - await _operatorManagementHelper.ClickEditOperatorButton(); - } - - #endregion - - #region Edit Operations Steps - - [When(@"the user updates the operator name to ""(.*)""")] - public async Task WhenTheUserUpdatesTheOperatorNameTo(string newName) - { - await _operatorManagementHelper.UpdateOperatorName(newName); - } - - [When(@"the user updates the custom merchant number requirement to checked")] - public async Task WhenTheUserUpdatesTheCustomMerchantNumberRequirementToChecked() - { - await _operatorManagementHelper.UpdateCustomMerchantNumberRequirement(true); - } - - [When(@"the user updates the custom terminal number requirement to checked")] - public async Task WhenTheUserUpdatesTheCustomTerminalNumberRequirementToChecked() - { - await _operatorManagementHelper.UpdateCustomTerminalNumberRequirement(true); - } - - [When(@"the user clicks the Save Changes button")] - public async Task WhenTheUserClicksTheSaveChangesButton() - { - await _operatorManagementHelper.ClickSaveChangesButton(); - } - - [When(@"the user enters ""(.*)"" as the operator name")] - public async Task WhenTheUserEntersAsTheOperatorName(string operatorName) - { - await _operatorManagementHelper.EnterOperatorName(operatorName); - } - - [When(@"the user clicks the Create Operator button")] - public async Task WhenTheUserClicksTheCreateOperatorButton() - { - await _operatorManagementHelper.ClickCreateOperatorButton(); - } - - #endregion - - #region Success/Error Message Steps - - [Then(@"a success message is displayed")] - public async Task ThenASuccessMessageIsDisplayed() - { - await _operatorManagementHelper.VerifySuccessMessageIsDisplayed(); - } - - [Then(@"a success message is displayed or user is redirected to operator list")] - public async Task ThenASuccessMessageIsDisplayedOrUserIsRedirectedToOperatorList() - { - // Check if either success message is shown or user was redirected - try - { - await _operatorManagementHelper.VerifySuccessMessageIsDisplayed(); - } - catch (Exception) - { - // If no success message found, check if user was redirected to the list page instead - // This handles the case where the app navigates away after successful creation - await _operatorManagementHelper.VerifyRedirectedToOperatorList(); - } - } - - [Then(@"the success message contains ""(.*)""")] - public async Task ThenTheSuccessMessageContains(string expectedMessage) - { - await _operatorManagementHelper.VerifySuccessMessageContains(expectedMessage); - } - - [Then(@"a validation error is displayed for operator name")] - public async Task ThenAValidationErrorIsDisplayedForOperatorName() - { - await _operatorManagementHelper.VerifyValidationErrorForOperatorName(); - } - - #endregion -} diff --git a/EstateManagementUI.IntegrationTests/Steps/ReportingSteps.cs b/EstateManagementUI.IntegrationTests/Steps/ReportingSteps.cs deleted file mode 100644 index c0541e00..00000000 --- a/EstateManagementUI.IntegrationTests/Steps/ReportingSteps.cs +++ /dev/null @@ -1,618 +0,0 @@ -using Microsoft.Playwright; -using Reqnroll; -using EstateManagementUI.IntegrationTests.Common; - -namespace EstateManagementUI.IntegrationTests.Steps; - -/// -/// Step definitions for Reporting integration tests -/// Links feature file scenarios to browser automation code -/// -[Binding] -public class ReportingSteps -{ - private readonly IPage _page; - private readonly ReportingPageHelper _reportingHelper; - private readonly ScenarioContext _scenarioContext; - - public ReportingSteps(ScenarioContext scenarioContext) - { - _scenarioContext = scenarioContext; - _page = scenarioContext.ScenarioContainer.Resolve(); - - // Get base URL from environment variable or use default - var baseUrl = Environment.GetEnvironmentVariable("APP_URL") ?? "https://localhost:5001"; - _reportingHelper = new ReportingPageHelper(_page, baseUrl); - } - - #region Navigation Steps - - [Given(@"the user navigates to the Reporting Dashboard")] - [When(@"the user navigates to the Reporting Dashboard")] - public async Task GivenTheUserNavigatesToTheReportingDashboard() - { - await _reportingHelper.NavigateToReportingDashboard(); - } - - [When(@"the user navigates to the Transaction Detail Report")] - public async Task WhenTheUserNavigatesToTheTransactionDetailReport() - { - await _reportingHelper.NavigateToTransactionDetailReport(); - } - - [When(@"the user navigates to the Transaction Summary by Merchant Report")] - public async Task WhenTheUserNavigatesToTheTransactionSummaryByMerchantReport() - { - await _reportingHelper.NavigateToTransactionSummaryMerchantReport(); - } - - [When(@"the user navigates to the Transaction Summary by Operator Report")] - public async Task WhenTheUserNavigatesToTheTransactionSummaryByOperatorReport() - { - await _reportingHelper.NavigateToTransactionSummaryOperatorReport(); - } - - [When(@"the user navigates to the Product Performance Report")] - public async Task WhenTheUserNavigatesToTheProductPerformanceReport() - { - await _reportingHelper.NavigateToProductPerformanceReport(); - } - - [When(@"the user navigates to the Settlement Summary Report")] - public async Task WhenTheUserNavigatesToTheSettlementSummaryReport() - { - await _reportingHelper.NavigateToSettlementSummaryReport(); - } - - [When(@"the user navigates to the Settlement Reconciliation Report")] - public async Task WhenTheUserNavigatesToTheSettlementReconciliationReport() - { - await _reportingHelper.NavigateToSettlementReconciliationReport(); - } - - [When(@"the user navigates to the Merchant Settlement History Report")] - public async Task WhenTheUserNavigatesToTheMerchantSettlementHistoryReport() - { - await _reportingHelper.NavigateToMerchantSettlementHistoryReport(); - } - - [When(@"the user navigates to the Analytical Charts Report")] - public async Task WhenTheUserNavigatesToTheAnalyticalChartsReport() - { - await _reportingHelper.NavigateToAnalyticalChartsReport(); - } - - #endregion - - #region Authentication/Role Steps - - [Given(@"the user is authenticated as (?:an|a) ""(.*)"" user")] - public async Task GivenTheUserIsAuthenticatedAsAUser(string role) - { - // Store the role in scenario context for reference - _scenarioContext["UserRole"] = role; - - // Note: This step assumes the application will be started in test mode - // with the appropriate role already configured. The actual authentication - // setup will be handled when the application startup is implemented. - await Task.CompletedTask; - } - - #endregion - - #region Reporting Dashboard Verification Steps - - [Then(@"the Reporting Dashboard page is displayed")] - public async Task ThenTheReportingDashboardPageIsDisplayed() - { - await _reportingHelper.VerifyReportingDashboardPageIsDisplayed(); - } - - [Then(@"the page title is ""(.*)""")] - public async Task ThenThePageTitleIs(string expectedTitle) - { - await _reportingHelper.VerifyPageTitle(expectedTitle); - } - - [Then(@"the Transaction Reporting section is displayed")] - public async Task ThenTheTransactionReportingSectionIsDisplayed() - { - await _reportingHelper.VerifyTransactionReportingSectionIsDisplayed(); - } - - [Then(@"the Settlement Reporting section is displayed")] - public async Task ThenTheSettlementReportingSectionIsDisplayed() - { - await _reportingHelper.VerifySettlementReportingSectionIsDisplayed(); - } - - [Then(@"the Reconciliation section is displayed")] - public async Task ThenTheReconciliationSectionIsDisplayed() - { - await _reportingHelper.VerifyReconciliationSectionIsDisplayed(); - } - - [Then(@"the KPI Reporting section is displayed")] - public async Task ThenTheKpiReportingSectionIsDisplayed() - { - await _reportingHelper.VerifyKpiReportingSectionIsDisplayed(); - } - - #endregion - - #region Report Page Verification Steps - - [Then(@"the Transaction Detail Report page is displayed")] - public async Task ThenTheTransactionDetailReportPageIsDisplayed() - { - await _reportingHelper.VerifyReportPageIsDisplayed("Transaction Detail Report"); - } - - [Then(@"the Transaction Summary by Merchant page is displayed")] - public async Task ThenTheTransactionSummaryByMerchantPageIsDisplayed() - { - await _reportingHelper.VerifyReportPageIsDisplayed("Transaction Summary by Merchant"); - } - - [Then(@"the Transaction Summary by Operator page is displayed")] - public async Task ThenTheTransactionSummaryByOperatorPageIsDisplayed() - { - await _reportingHelper.VerifyReportPageIsDisplayed("Transaction Summary by Operator"); - } - - [Then(@"the Product Performance Report page is displayed")] - public async Task ThenTheProductPerformanceReportPageIsDisplayed() - { - await _reportingHelper.VerifyReportPageIsDisplayed("Product Performance Report"); - } - - [Then(@"the Settlement Summary Report page is displayed")] - public async Task ThenTheSettlementSummaryReportPageIsDisplayed() - { - await _reportingHelper.VerifyReportPageIsDisplayed("Settlement Summary Report"); - } - - [Then(@"the Settlement Reconciliation Report page is displayed")] - public async Task ThenTheSettlementReconciliationReportPageIsDisplayed() - { - await _reportingHelper.VerifyReportPageIsDisplayed("Settlement vs Transaction Reconciliation Report"); - } - - [Then(@"the Merchant Settlement History page is displayed")] - public async Task ThenTheMerchantSettlementHistoryPageIsDisplayed() - { - await _reportingHelper.VerifyReportPageIsDisplayed("Merchant Settlement History"); - } - - [Then(@"the Analytical Charts page is displayed")] - public async Task ThenTheAnalyticalChartsPageIsDisplayed() - { - await _reportingHelper.VerifyReportPageIsDisplayed("Analytical Charts"); - } - - [Then(@"the filters section is displayed")] - public async Task ThenTheFiltersSectionIsDisplayed() - { - await _reportingHelper.VerifyFiltersSectionIsDisplayed(); - } - - [Then(@"the transaction details grid is displayed")] - public async Task ThenTheTransactionDetailsGridIsDisplayed() - { - await _reportingHelper.VerifyTransactionDetailsGridIsDisplayed(); - } - - [Then(@"the merchant summary grid is displayed")] - public async Task ThenTheMerchantSummaryGridIsDisplayed() - { - await _reportingHelper.VerifyMerchantSummaryGridIsDisplayed(); - } - - [Then(@"the operator summary grid is displayed")] - public async Task ThenTheOperatorSummaryGridIsDisplayed() - { - await _reportingHelper.VerifyOperatorSummaryGridIsDisplayed(); - } - - [Then(@"the product performance grid is displayed")] - public async Task ThenTheProductPerformanceGridIsDisplayed() - { - await _reportingHelper.VerifyProductPerformanceGridIsDisplayed(); - } - - [Then(@"the settlement summary grid is displayed")] - public async Task ThenTheSettlementSummaryGridIsDisplayed() - { - await _reportingHelper.VerifySettlementSummaryGridIsDisplayed(); - } - - [Then(@"the reconciliation grid is displayed")] - public async Task ThenTheReconciliationGridIsDisplayed() - { - await _reportingHelper.VerifyReconciliationGridIsDisplayed(); - } - - [Then(@"the settlement history grid is displayed")] - public async Task ThenTheSettlementHistoryGridIsDisplayed() - { - await _reportingHelper.VerifySettlementHistoryGridIsDisplayed(); - } - - [Then(@"the analytical charts are displayed")] - public async Task ThenTheAnalyticalChartsAreDisplayed() - { - await _reportingHelper.VerifyAnalyticalChartsAreDisplayed(); - } - - [Then(@"the product performance chart is displayed")] - public async Task ThenTheProductPerformanceChartIsDisplayed() - { - await _reportingHelper.VerifyProductPerformanceChartIsDisplayed(); - } - - #endregion - - #region KPI Verification Steps - - [Then(@"the Total Transactions KPI is displayed")] - public async Task ThenTheTotalTransactionsKpiIsDisplayed() - { - await _reportingHelper.VerifyKpiIsDisplayed("Total Transactions"); - } - - [Then(@"the Total Value KPI is displayed")] - public async Task ThenTheTotalValueKpiIsDisplayed() - { - await _reportingHelper.VerifyKpiIsDisplayed("Total Value"); - } - - [Then(@"the Average Transaction KPI is displayed")] - public async Task ThenTheAverageTransactionKpiIsDisplayed() - { - await _reportingHelper.VerifyKpiIsDisplayed("Average Transaction"); - } - - [Then(@"the Total Merchants KPI is displayed")] - public async Task ThenTheTotalMerchantsKpiIsDisplayed() - { - await _reportingHelper.VerifyKpiIsDisplayed("Total Merchants"); - } - - [Then(@"the Total Products KPI is displayed")] - public async Task ThenTheTotalProductsKpiIsDisplayed() - { - await _reportingHelper.VerifyKpiIsDisplayed("Total Products"); - } - - [Then(@"the Average per Product KPI is displayed")] - public async Task ThenTheAveragePerProductKpiIsDisplayed() - { - await _reportingHelper.VerifyKpiIsDisplayed("Average per Product"); - } - - [Then(@"the Gross Value KPI is displayed")] - public async Task ThenTheGrossValueKpiIsDisplayed() - { - await _reportingHelper.VerifyKpiIsDisplayed("Gross Value"); - } - - [Then(@"the Total Fees KPI is displayed")] - public async Task ThenTheTotalFeesKpiIsDisplayed() - { - await _reportingHelper.VerifyKpiIsDisplayed("Total Fees"); - } - - [Then(@"the Net Settlement Value KPI is displayed")] - public async Task ThenTheNetSettlementValueKpiIsDisplayed() - { - await _reportingHelper.VerifyKpiIsDisplayed("Net Settlement Value"); - } - - [Then(@"the Total Transactions KPI is greater than ""(.*)""")] - public async Task ThenTheTotalTransactionsKpiIsGreaterThan(int minValue) - { - await _reportingHelper.VerifyTotalTransactionsKpiIsGreaterThan(minValue); - } - - #endregion - - #region Filter Interaction Steps - - [When(@"the user sets the start date to ""(.*)"" days ago")] - public async Task WhenTheUserSetsTheStartDateToDaysAgo(int daysAgo) - { - await _reportingHelper.SetStartDate(daysAgo); - } - - [When(@"the user sets the end date to today")] - public async Task WhenTheUserSetsTheEndDateToToday() - { - await _reportingHelper.SetEndDateToToday(); - } - - [When(@"the user selects a merchant from the filter dropdown")] - public async Task WhenTheUserSelectsAMerchantFromTheFilterDropdown() - { - await _reportingHelper.SelectMerchantFromFilter(); - } - - [When(@"the user selects an operator from the filter dropdown")] - public async Task WhenTheUserSelectsAnOperatorFromTheFilterDropdown() - { - await _reportingHelper.SelectOperatorFromFilter(); - } - - [When(@"the user selects a product from the filter dropdown")] - public async Task WhenTheUserSelectsAProductFromTheFilterDropdown() - { - await _reportingHelper.SelectProductFromFilter(); - } - - [When(@"the user selects ""(.*)"" from the status filter dropdown")] - public async Task WhenTheUserSelectsFromTheStatusFilterDropdown(string status) - { - await _reportingHelper.SelectStatusFromFilter(status); - } - - [When(@"the user clicks Apply Filters")] - public async Task WhenTheUserClicksApplyFilters() - { - await _reportingHelper.ClickApplyFilters(); - } - - [When(@"the user clicks Clear Filters")] - public async Task WhenTheUserClicksClearFilters() - { - await _reportingHelper.ClickClearFilters(); - } - - [When(@"the user clicks Refresh")] - public async Task WhenTheUserClicksRefresh() - { - await _reportingHelper.ClickRefresh(); - } - - #endregion - - #region Data Verification Steps - - [Then(@"the transaction details grid displays filtered results")] - public async Task ThenTheTransactionDetailsGridDisplaysFilteredResults() - { - await _reportingHelper.VerifyFilteredResultsDisplayed(); - } - - [Then(@"the transaction details grid displays results for the selected merchant")] - public async Task ThenTheTransactionDetailsGridDisplaysResultsForTheSelectedMerchant() - { - await _reportingHelper.VerifyFilteredResultsDisplayed(); - } - - [Then(@"all displayed transactions match the selected merchant")] - public async Task ThenAllDisplayedTransactionsMatchTheSelectedMerchant() - { - await _reportingHelper.VerifyAllTransactionsMatchSelectedMerchant(); - } - - [Then(@"the transaction details grid displays results for the selected operator")] - public async Task ThenTheTransactionDetailsGridDisplaysResultsForTheSelectedOperator() - { - await _reportingHelper.VerifyFilteredResultsDisplayed(); - } - - [Then(@"all displayed transactions match the selected operator")] - public async Task ThenAllDisplayedTransactionsMatchTheSelectedOperator() - { - await _reportingHelper.VerifyAllTransactionsMatchSelectedOperator(); - } - - [Then(@"the transaction details grid displays results for the selected product")] - public async Task ThenTheTransactionDetailsGridDisplaysResultsForTheSelectedProduct() - { - await _reportingHelper.VerifyFilteredResultsDisplayed(); - } - - [Then(@"all displayed transactions match the selected product")] - public async Task ThenAllDisplayedTransactionsMatchTheSelectedProduct() - { - await _reportingHelper.VerifyAllTransactionsMatchSelectedProduct(); - } - - [Then(@"all filter selections are reset to default values")] - public async Task ThenAllFilterSelectionsAreResetToDefaultValues() - { - await _reportingHelper.VerifyFiltersAreResetToDefaultValues(); - } - - [Then(@"the transaction details grid displays unfiltered results")] - public async Task ThenTheTransactionDetailsGridDisplaysUnfilteredResults() - { - await _reportingHelper.VerifyUnfilteredResultsDisplayed(); - } - - [Then(@"the merchant summary grid displays filtered results")] - public async Task ThenTheMerchantSummaryGridDisplaysFilteredResults() - { - await _reportingHelper.VerifyFilteredResultsDisplayed(); - } - - [Then(@"the merchant summary grid displays results for the selected merchant")] - public async Task ThenTheMerchantSummaryGridDisplaysResultsForTheSelectedMerchant() - { - await _reportingHelper.VerifyFilteredResultsDisplayed(); - } - - [Then(@"the merchant summary grid displays results for the selected operator")] - public async Task ThenTheMerchantSummaryGridDisplaysResultsForTheSelectedOperator() - { - await _reportingHelper.VerifyFilteredResultsDisplayed(); - } - - [Then(@"the operator summary grid displays filtered results")] - public async Task ThenTheOperatorSummaryGridDisplaysFilteredResults() - { - await _reportingHelper.VerifyFilteredResultsDisplayed(); - } - - [Then(@"the operator summary grid displays results for the selected operator")] - public async Task ThenTheOperatorSummaryGridDisplaysResultsForTheSelectedOperator() - { - await _reportingHelper.VerifyFilteredResultsDisplayed(); - } - - [Then(@"the product performance grid displays filtered results")] - public async Task ThenTheProductPerformanceGridDisplaysFilteredResults() - { - await _reportingHelper.VerifyFilteredResultsDisplayed(); - } - - [Then(@"the settlement summary grid displays filtered results")] - public async Task ThenTheSettlementSummaryGridDisplaysFilteredResults() - { - await _reportingHelper.VerifyFilteredResultsDisplayed(); - } - - [Then(@"the settlement summary grid displays results for the selected merchant")] - public async Task ThenTheSettlementSummaryGridDisplaysResultsForTheSelectedMerchant() - { - await _reportingHelper.VerifyFilteredResultsDisplayed(); - } - - [Then(@"the settlement summary grid displays only settled settlements")] - public async Task ThenTheSettlementSummaryGridDisplaysOnlySettledSettlements() - { - await _reportingHelper.VerifyOnlySettledSettlementsDisplayed(); - } - - [Then(@"the reconciliation grid displays filtered results")] - public async Task ThenTheReconciliationGridDisplaysFilteredResults() - { - await _reportingHelper.VerifyFilteredResultsDisplayed(); - } - - [Then(@"the reconciliation grid displays results for the selected merchant")] - public async Task ThenTheReconciliationGridDisplaysResultsForTheSelectedMerchant() - { - await _reportingHelper.VerifyFilteredResultsDisplayed(); - } - - [Then(@"the settlement history grid displays filtered results")] - public async Task ThenTheSettlementHistoryGridDisplaysFilteredResults() - { - await _reportingHelper.VerifyFilteredResultsDisplayed(); - } - - [Then(@"the settlement history grid displays results for the selected merchant")] - public async Task ThenTheSettlementHistoryGridDisplaysResultsForTheSelectedMerchant() - { - await _reportingHelper.VerifyFilteredResultsDisplayed(); - } - - [Then(@"the analytical charts display filtered results")] - public async Task ThenTheAnalyticalChartsDisplayFilteredResults() - { - await _reportingHelper.VerifyAnalyticalChartsAreDisplayed(); - } - - #endregion - - #region Sorting and Pagination Steps - - [When(@"the user clicks on the ""(.*)"" column header")] - public async Task WhenTheUserClicksOnTheColumnHeader(string columnName) - { - await _reportingHelper.ClickColumnHeader(columnName); - } - - [Then(@"the transaction details grid is sorted by ""(.*)"" in ascending order")] - public async Task ThenTheTransactionDetailsGridIsSortedByInAscendingOrder(string columnName) - { - await _reportingHelper.VerifyGridIsSortedByColumnAscending(columnName); - } - - [When(@"the transaction details grid has multiple pages")] - public async Task WhenTheTransactionDetailsGridHasMultiplePages() - { - await _reportingHelper.VerifyGridHasMultiplePages(); - } - - [When(@"the user clicks the Next Page button")] - public async Task WhenTheUserClicksTheNextPageButton() - { - await _reportingHelper.ClickNextPageButton(); - } - - [Then(@"the transaction details grid displays the next page of results")] - public async Task ThenTheTransactionDetailsGridDisplaysTheNextPageOfResults() - { - await _reportingHelper.VerifyNextPageOfResultsDisplayed(); - } - - #endregion - - #region View Toggle Steps - - [When(@"the user clicks Chart View button")] - public async Task WhenTheUserClicksChartViewButton() - { - await _reportingHelper.ClickChartViewButton(); - } - - [When(@"the user clicks Grid View button")] - public async Task WhenTheUserClicksGridViewButton() - { - await _reportingHelper.ClickGridViewButton(); - } - - #endregion - - #region Chart Type Steps - - [When(@"the user selects the Volume chart type")] - public async Task WhenTheUserSelectsTheVolumeChartType() - { - await _reportingHelper.SelectChartType("Volume"); - } - - [When(@"the user selects the Value chart type")] - public async Task WhenTheUserSelectsTheValueChartType() - { - await _reportingHelper.SelectChartType("Value"); - } - - [Then(@"the volume chart is displayed")] - public async Task ThenTheVolumeChartIsDisplayed() - { - await _reportingHelper.VerifyVolumeChartIsDisplayed(); - } - - [Then(@"the value chart is displayed")] - public async Task ThenTheValueChartIsDisplayed() - { - await _reportingHelper.VerifyValueChartIsDisplayed(); - } - - #endregion - - #region Drill-Down Steps - - [When(@"the user clicks View Details for a merchant")] - public async Task WhenTheUserClicksViewDetailsForAMerchant() - { - await _reportingHelper.ClickViewDetailsForMerchant(); - } - - [Then(@"the user is navigated to the Transaction Detail Report")] - public async Task ThenTheUserIsNavigatedToTheTransactionDetailReport() - { - await _reportingHelper.VerifyNavigatedToTransactionDetailReport(); - } - - [Then(@"the merchant filter is pre-populated")] - public async Task ThenTheMerchantFilterIsPrePopulated() - { - await _reportingHelper.VerifyMerchantFilterIsPrePopulated(); - } - - #endregion -} diff --git a/EstateManagementUI.IntegrationTests/testdiag.host.26-06-19_13-41-30_03760_5.txt b/EstateManagementUI.IntegrationTests/testdiag.host.26-06-19_13-41-30_03760_5.txt new file mode 100644 index 00000000..409bd18c --- /dev/null +++ b/EstateManagementUI.IntegrationTests/testdiag.host.26-06-19_13-41-30_03760_5.txt @@ -0,0 +1,742 @@ +TpTrace Verbose: 0 : 53008, 2, 2026/06/19, 13:41:30.177, 6199776441061, testhost.dll, Version: 18.6.0 Current process architecture: X64 +TpTrace Verbose: 0 : 53008, 2, 2026/06/19, 13:41:30.180, 6199776471756, testhost.dll, Runtime location: C:\Program Files\dotnet\shared\Microsoft.NETCore.App\10.0.9 +TpTrace Information: 0 : 53008, 2, 2026/06/19, 13:41:30.183, 6199776496396, testhost.dll, DefaultEngineInvoker.Invoke: Testhost process started with args :[--port, 62255],[--endpoint, 127.0.0.1:062255],[--role, client],[--parentprocessid, 48056],[--diag, D:\Projects\TransactionProcessing\EstateManagementUI\EstateManagementUI.IntegrationTests\testdiag.host.26-06-19_13-41-30_03760_5.txt],[--tracelevel, 4],[--telemetryoptedin, false] +TpTrace Information: 0 : 53008, 2, 2026/06/19, 13:41:30.183, 6199776499689, testhost.dll, Setting up debug trace listener. +TpTrace Verbose: 0 : 53008, 2, 2026/06/19, 13:41:30.183, 6199776500663, testhost.dll, TestPlatformTraceListener.Setup: Replacing listener System.Diagnostics.DefaultTraceListener with TestHostTraceListener. +TpTrace Verbose: 0 : 53008, 2, 2026/06/19, 13:41:30.183, 6199776501685, testhost.dll, TestPlatformTraceListener.Setup: Added test platform trace listener. +TpTrace Information: 0 : 53008, 2, 2026/06/19, 13:41:30.184, 6199776505579, testhost.dll, DefaultEngineInvoker.SetParentProcessExitCallback: Monitoring parent process with id: '48056' +TpTrace Information: 0 : 53008, 2, 2026/06/19, 13:41:30.187, 6199776535396, testhost.dll, DefaultEngineInvoker.GetConnectionInfo: Initialize communication on endpoint address: '127.0.0.1:062255' +TpTrace Information: 0 : 53008, 2, 2026/06/19, 13:41:30.203, 6199776699189, testhost.dll, SocketClient.Start: connecting to server endpoint: 127.0.0.1:062255 +TpTrace Information: 0 : 53008, 9, 2026/06/19, 13:41:30.213, 6199776792625, testhost.dll, SocketClient.OnServerConnected: connected to server endpoint: 127.0.0.1:062255 +TpTrace Information: 0 : 53008, 2, 2026/06/19, 13:41:30.213, 6199776794681, testhost.dll, DefaultEngineInvoker.Invoke: Start Request Processing. +TpTrace Information: 0 : 53008, 11, 2026/06/19, 13:41:30.215, 6199776819239, testhost.dll, DefaultEngineInvoker.StartProcessingAsync: Connected to vstest.console, Starting process requests. +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:41:30.215, 6199776821651, testhost.dll, MulticastDelegateUtilities.SafeInvoke: SocketClient: ServerConnected: Invoking callback 1/1 for Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.TestRequestHandler., took 0 ms. +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:41:30.216, 6199776822132, testhost.dll, Connected to server, and starting MessageLoopAsync +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:41:30.219, 6199776857741, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 0 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:41:30.256, 6199777222416, testhost.dll, TcpClientExtensions.MessageLoopAsync: NotifyDataAvailable remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 +TpTrace Information: 0 : 53008, 9, 2026/06/19, 13:41:30.259, 6199777254500, testhost.dll, TestRequestHandler.OnMessageReceived: received message: (ProtocolVersion) -> {"MessageType":"ProtocolVersion","Payload":7} +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:41:30.377, 6199778441507, testhost.dll, TestRequestHandler.SendData: sending data from testhost: {"Version":7,"MessageType":"TestSession.Message","Payload":{"MessageLevel":0,"Message":"Logging TestHost Diagnostics in file: D:\\Projects\\TransactionProcessing\\EstateManagementUI\\EstateManagementUI.IntegrationTests\\testdiag.host.26-06-19_13-41-30_03760_5.txt"}} +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:41:30.378, 6199778444335, testhost.dll, MulticastDelegateUtilities.SafeInvoke: LengthPrefixCommunicationChannel: MessageReceived: Invoking callback 1/1 for Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.TestRequestHandler., took 121 ms. +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:41:30.378, 6199778445525, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 158 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:41:30.379, 6199778461039, testhost.dll, TcpClientExtensions.MessageLoopAsync: NotifyDataAvailable remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 +TpTrace Information: 0 : 53008, 9, 2026/06/19, 13:41:30.380, 6199778465470, testhost.dll, TestRequestHandler.OnMessageReceived: received message: (TestExecution.Initialize) -> {"Version":7,"MessageType":"TestExecution.Initialize","Payload":["D:\\Projects\\TransactionProcessing\\EstateManagementUI\\EstateManagementUI.IntegrationTests\\bin\\Debug\\net10.0\\NUnit3.TestAdapter.dll"]} +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:41:30.389, 6199778553022, testhost.dll, MulticastDelegateUtilities.SafeInvoke: LengthPrefixCommunicationChannel: MessageReceived: Invoking callback 1/1 for Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.TestRequestHandler., took 8 ms. +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:41:30.389, 6199778553769, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 10 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:41:30.389, 6199778554330, testhost.dll, TcpClientExtensions.MessageLoopAsync: NotifyDataAvailable remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 +TpTrace Information: 0 : 53008, 9, 2026/06/19, 13:41:30.389, 6199778555380, testhost.dll, TestRequestHandler.OnMessageReceived: received message: (TestExecution.StartWithSources) -> {"Version":7,"MessageType":"TestExecution.StartWithSources","Payload":{"AdapterSourceMap":{"_none_":["D:\\Projects\\TransactionProcessing\\EstateManagementUI\\EstateManagementUI.IntegrationTests\\bin\\Debug\\net10.0\\EstateManagementUI.IntegrationTests.dll"]},"RunSettings":"\r\n \r\n D:\\Projects\\TransactionProcessing\\EstateManagementUI\\EstateManagementUI.IntegrationTests\\TestResults\r\n .NETCoreApp,Version=v10.0\r\n C:\\Users\\stuar\\.nuget\\packages\\coverlet.collector\\10.0.1\\build\\net10.0\\\r\n False\r\n False\r\n \r\n \r\n \r\n \r\n \r\n minimal\r\n \r\n \r\n \r\n \r\n","TestExecutionContext":{"FrequencyOfRunStatsChangeEvent":10,"RunStatsChangeEventTimeout":"00:00:01.5000000","InIsolation":false,"KeepAlive":false,"AreTestCaseLevelEventsRequired":false,"IsDebug":false,"TestCaseFilter":"FullyQualifiedName~AdministratorsSeeTheDashboardWelcomePanel","FilterOptions":null},"Package":null}} +TpTrace Information: 0 : 53008, 4, 2026/06/19, 13:41:30.389, 6199778560534, testhost.dll, TestRequestHandler.OnMessageReceived: Running job 'TestExecution.Initialize'. +TpTrace Verbose: 0 : 53008, 4, 2026/06/19, 13:41:30.392, 6199778591943, testhost.dll, TestExecutorService: Loading the extensions +TpTrace Verbose: 0 : 53008, 4, 2026/06/19, 13:41:30.394, 6199778610909, testhost.dll, TestPluginCache.DiscoverTestExtensions: finding test extensions in assemblies ends with: TestAdapter.dll TPluginInfo: Microsoft.VisualStudio.TestPlatform.Common.ExtensionFramework.Utilities.TestExecutorPluginInformation TExtension: Microsoft.VisualStudio.TestPlatform.ObjectModel.Adapter.ITestExecutor +TpTrace Verbose: 0 : 53008, 4, 2026/06/19, 13:41:30.396, 6199778629842, testhost.dll, TestPluginCache.GetExtensionPaths: Filtered extension paths: +TpTrace Verbose: 0 : 53008, 4, 2026/06/19, 13:41:30.397, 6199778632962, testhost.dll, TestPluginCache.GetExtensionPaths: Added default extension paths: D:\Projects\TransactionProcessing\EstateManagementUI\EstateManagementUI.IntegrationTests\bin\Debug\net10.0\NUnit3.TestAdapter.dll +TpTrace Verbose: 0 : 53008, 4, 2026/06/19, 13:41:30.397, 6199778633394, testhost.dll, TestPluginCache.GetExtensionPaths: Added unfilterableExtensionPaths: +TpTrace Information: 0 : 53008, 4, 2026/06/19, 13:41:30.398, 6199778651296, testhost.dll, AssemblyResolver.ctor: Creating AssemblyResolver with searchDirectories D:\Projects\TransactionProcessing\EstateManagementUI\EstateManagementUI.IntegrationTests\bin\Debug\net10.0 +TpTrace Verbose: 0 : 53008, 4, 2026/06/19, 13:41:30.400, 6199778662671, testhost.dll, TestPluginCache.DiscoverTestExtensions: Discovering the extensions using extension path. +TpTrace Verbose: 0 : 53008, 4, 2026/06/19, 13:41:30.400, 6199778663628, testhost.dll, TestPluginCache.GetExtensionPaths: Filtered extension paths: +TpTrace Verbose: 0 : 53008, 4, 2026/06/19, 13:41:30.400, 6199778664109, testhost.dll, TestPluginCache.GetExtensionPaths: Added default extension paths: D:\Projects\TransactionProcessing\EstateManagementUI\EstateManagementUI.IntegrationTests\bin\Debug\net10.0\NUnit3.TestAdapter.dll +TpTrace Verbose: 0 : 53008, 4, 2026/06/19, 13:41:30.400, 6199778664537, testhost.dll, TestPluginCache.GetExtensionPaths: Added unfilterableExtensionPaths: +TpTrace Verbose: 0 : 53008, 4, 2026/06/19, 13:41:30.400, 6199778665420, testhost.dll, TestPluginCache.DiscoverTestExtensions: Discovering the extensions using allExtensionPaths: D:\Projects\TransactionProcessing\EstateManagementUI\EstateManagementUI.IntegrationTests\bin\Debug\net10.0\NUnit3.TestAdapter.dll +TpTrace Information: 0 : 53008, 4, 2026/06/19, 13:41:30.401, 6199778673042, testhost.dll, AssemblyResolver.AddSearchDirectories: Adding more searchDirectories D:\Projects\TransactionProcessing\EstateManagementUI\EstateManagementUI.IntegrationTests\bin\Debug\net10.0 +TpTrace Information: 0 : 53008, 4, 2026/06/19, 13:41:30.403, 6199778699818, testhost.dll, AssemblyResolver.OnResolve: NUnit3.TestAdapter: Resolving assembly. +TpTrace Information: 0 : 53008, 4, 2026/06/19, 13:41:30.403, 6199778700647, testhost.dll, AssemblyResolver.OnResolve: NUnit3.TestAdapter: Searching in: 'D:\Projects\TransactionProcessing\EstateManagementUI\EstateManagementUI.IntegrationTests\bin\Debug\net10.0'. +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:41:30.412, 6199778787299, testhost.dll, MulticastDelegateUtilities.SafeInvoke: LengthPrefixCommunicationChannel: MessageReceived: Invoking callback 1/1 for Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.TestRequestHandler., took 23 ms. +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:41:30.412, 6199778788488, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 23 ms +TpTrace Information: 0 : 53008, 4, 2026/06/19, 13:41:30.412, 6199778791779, testhost.dll, AssemblyResolver.OnResolve: NUnit3.TestAdapter: Loading assembly 'D:\Projects\TransactionProcessing\EstateManagementUI\EstateManagementUI.IntegrationTests\bin\Debug\net10.0\NUnit3.TestAdapter.dll'. +TpTrace Information: 0 : 53008, 4, 2026/06/19, 13:41:30.413, 6199778796180, testhost.dll, AssemblyResolver.OnResolve: Resolved assembly: NUnit3.TestAdapter, from path: D:\Projects\TransactionProcessing\EstateManagementUI\EstateManagementUI.IntegrationTests\bin\Debug\net10.0\NUnit3.TestAdapter.dll +TpTrace Verbose: 0 : 53008, 4, 2026/06/19, 13:41:30.426, 6199778930915, testhost.dll, MetadataReaderExtensionsHelper: Discovering extensions inside assembly 'NUnit3.TestAdapter, Version=1.0.0.0, Culture=neutral, PublicKeyToken=4cb40d35494691ac' file path 'D:\Projects\TransactionProcessing\EstateManagementUI\EstateManagementUI.IntegrationTests\bin\Debug\net10.0\NUnit3.TestAdapter.dll' +TpTrace Information: 0 : 53008, 4, 2026/06/19, 13:41:30.429, 6199778952877, testhost.dll, AssemblyResolver.OnResolve: nunit.engine.api: Resolving assembly. +TpTrace Information: 0 : 53008, 4, 2026/06/19, 13:41:30.429, 6199778954433, testhost.dll, AssemblyResolver.OnResolve: nunit.engine.api: Searching in: 'D:\Projects\TransactionProcessing\EstateManagementUI\EstateManagementUI.IntegrationTests\bin\Debug\net10.0'. +TpTrace Information: 0 : 53008, 4, 2026/06/19, 13:41:30.429, 6199778957047, testhost.dll, AssemblyResolver.OnResolve: nunit.engine.api: Loading assembly 'D:\Projects\TransactionProcessing\EstateManagementUI\EstateManagementUI.IntegrationTests\bin\Debug\net10.0\nunit.engine.api.dll'. +TpTrace Information: 0 : 53008, 4, 2026/06/19, 13:41:30.429, 6199778960355, testhost.dll, AssemblyResolver.OnResolve: Resolved assembly: nunit.engine.api, from path: D:\Projects\TransactionProcessing\EstateManagementUI\EstateManagementUI.IntegrationTests\bin\Debug\net10.0\nunit.engine.api.dll +TpTrace Information: 0 : 53008, 4, 2026/06/19, 13:41:30.433, 6199779002013, testhost.dll, GetTestExtensionFromType: Register extension with identifier data 'executor://NUnit3TestExecutor' and type 'NUnit.VisualStudio.TestAdapter.NUnit3TestExecutor, NUnit3.TestAdapter, Version=1.0.0.0, Culture=neutral, PublicKeyToken=4cb40d35494691ac' inside file 'D:\Projects\TransactionProcessing\EstateManagementUI\EstateManagementUI.IntegrationTests\bin\Debug\net10.0\NUnit3.TestAdapter.dll' +TpTrace Verbose: 0 : 53008, 4, 2026/06/19, 13:41:30.435, 6199779021022, testhost.dll, TestPluginCache: Discovered the extensions using extension path ''. +TpTrace Verbose: 0 : 53008, 4, 2026/06/19, 13:41:30.436, 6199779026296, testhost.dll, TestPluginCache: Discoverers are ''. +TpTrace Verbose: 0 : 53008, 4, 2026/06/19, 13:41:30.436, 6199779027470, testhost.dll, TestPluginCache: Executors are 'executor://NUnit3TestExecutor'. +TpTrace Verbose: 0 : 53008, 4, 2026/06/19, 13:41:30.436, 6199779028533, testhost.dll, TestPluginCache: Executors2 are ''. +TpTrace Verbose: 0 : 53008, 4, 2026/06/19, 13:41:30.436, 6199779029463, testhost.dll, TestPluginCache: Setting providers are ''. +TpTrace Verbose: 0 : 53008, 4, 2026/06/19, 13:41:30.436, 6199779030298, testhost.dll, TestPluginCache: Loggers are ''. +TpTrace Verbose: 0 : 53008, 4, 2026/06/19, 13:41:30.436, 6199779031125, testhost.dll, TestPluginCache: TestHosts are ''. +TpTrace Verbose: 0 : 53008, 4, 2026/06/19, 13:41:30.436, 6199779031949, testhost.dll, TestPluginCache: DataCollectors are ''. +TpTrace Verbose: 0 : 53008, 4, 2026/06/19, 13:41:30.439, 6199779058279, testhost.dll, TestPluginCache.DiscoverTestExtensions: finding test extensions in assemblies ends with: TestAdapter.dll TPluginInfo: Microsoft.VisualStudio.TestPlatform.Common.ExtensionFramework.Utilities.TestExecutorPluginInformation2 TExtension: Microsoft.VisualStudio.TestPlatform.ObjectModel.Adapter.ITestExecutor2 +TpTrace Verbose: 0 : 53008, 4, 2026/06/19, 13:41:30.439, 6199779061062, testhost.dll, TestPluginCache.GetExtensionPaths: Filtered extension paths: +TpTrace Verbose: 0 : 53008, 4, 2026/06/19, 13:41:30.439, 6199779061640, testhost.dll, TestPluginCache.GetExtensionPaths: Added default extension paths: D:\Projects\TransactionProcessing\EstateManagementUI\EstateManagementUI.IntegrationTests\bin\Debug\net10.0\NUnit3.TestAdapter.dll +TpTrace Verbose: 0 : 53008, 4, 2026/06/19, 13:41:30.439, 6199779061984, testhost.dll, TestPluginCache.GetExtensionPaths: Added unfilterableExtensionPaths: +TpTrace Information: 0 : 53008, 4, 2026/06/19, 13:41:30.440, 6199779063563, testhost.dll, AssemblyResolver.AddSearchDirectories: Adding more searchDirectories D:\Projects\TransactionProcessing\EstateManagementUI\EstateManagementUI.IntegrationTests\bin\Debug\net10.0 +TpTrace Verbose: 0 : 53008, 4, 2026/06/19, 13:41:30.440, 6199779064076, testhost.dll, TestPluginCache.DiscoverTestExtensions: Discovering the extensions using extension path. +TpTrace Verbose: 0 : 53008, 4, 2026/06/19, 13:41:30.440, 6199779064443, testhost.dll, TestPluginCache.GetExtensionPaths: Filtered extension paths: +TpTrace Verbose: 0 : 53008, 4, 2026/06/19, 13:41:30.440, 6199779064806, testhost.dll, TestPluginCache.GetExtensionPaths: Added default extension paths: D:\Projects\TransactionProcessing\EstateManagementUI\EstateManagementUI.IntegrationTests\bin\Debug\net10.0\NUnit3.TestAdapter.dll +TpTrace Verbose: 0 : 53008, 4, 2026/06/19, 13:41:30.440, 6199779065151, testhost.dll, TestPluginCache.GetExtensionPaths: Added unfilterableExtensionPaths: +TpTrace Verbose: 0 : 53008, 4, 2026/06/19, 13:41:30.440, 6199779065488, testhost.dll, TestPluginCache.DiscoverTestExtensions: Discovering the extensions using allExtensionPaths: D:\Projects\TransactionProcessing\EstateManagementUI\EstateManagementUI.IntegrationTests\bin\Debug\net10.0\NUnit3.TestAdapter.dll +TpTrace Information: 0 : 53008, 4, 2026/06/19, 13:41:30.440, 6199779065923, testhost.dll, AssemblyResolver.AddSearchDirectories: Adding more searchDirectories D:\Projects\TransactionProcessing\EstateManagementUI\EstateManagementUI.IntegrationTests\bin\Debug\net10.0 +TpTrace Verbose: 0 : 53008, 4, 2026/06/19, 13:41:30.440, 6199779066640, testhost.dll, MetadataReaderExtensionsHelper: Discovering extensions inside assembly 'NUnit3.TestAdapter, Version=1.0.0.0, Culture=neutral, PublicKeyToken=4cb40d35494691ac' file path 'D:\Projects\TransactionProcessing\EstateManagementUI\EstateManagementUI.IntegrationTests\bin\Debug\net10.0\NUnit3.TestAdapter.dll' +TpTrace Verbose: 0 : 53008, 4, 2026/06/19, 13:41:30.441, 6199779076083, testhost.dll, TestPluginCache: Discovered the extensions using extension path ''. +TpTrace Verbose: 0 : 53008, 4, 2026/06/19, 13:41:30.441, 6199779076638, testhost.dll, TestPluginCache: Discoverers are ''. +TpTrace Verbose: 0 : 53008, 4, 2026/06/19, 13:41:30.441, 6199779077091, testhost.dll, TestPluginCache: Executors are 'executor://NUnit3TestExecutor'. +TpTrace Verbose: 0 : 53008, 4, 2026/06/19, 13:41:30.441, 6199779077617, testhost.dll, TestPluginCache: Executors2 are ''. +TpTrace Verbose: 0 : 53008, 4, 2026/06/19, 13:41:30.441, 6199779077902, testhost.dll, TestPluginCache: Setting providers are ''. +TpTrace Verbose: 0 : 53008, 4, 2026/06/19, 13:41:30.441, 6199779078160, testhost.dll, TestPluginCache: Loggers are ''. +TpTrace Verbose: 0 : 53008, 4, 2026/06/19, 13:41:30.441, 6199779078497, testhost.dll, TestPluginCache: TestHosts are ''. +TpTrace Verbose: 0 : 53008, 4, 2026/06/19, 13:41:30.441, 6199779078765, testhost.dll, TestPluginCache: DataCollectors are ''. +TpTrace Information: 0 : 53008, 4, 2026/06/19, 13:41:30.450, 6199779169685, testhost.dll, TestPluginManager.CreateTestExtension: Attempting to load test extension: NUnit.VisualStudio.TestAdapter.NUnit3TestExecutor +TpTrace Verbose: 0 : 53008, 4, 2026/06/19, 13:41:30.452, 6199779190379, testhost.dll, TestExecutorExtensionManager: Loading executor Microsoft.VisualStudio.TestPlatform.Common.ExtensionDecorators.SerialTestRunDecorator +TpTrace Verbose: 0 : 53008, 4, 2026/06/19, 13:41:30.452, 6199779191131, testhost.dll, TestExecutorService: Loaded the executors +TpTrace Verbose: 0 : 53008, 4, 2026/06/19, 13:41:30.453, 6199779200680, testhost.dll, TestPluginCache.DiscoverTestExtensions: finding test extensions in assemblies ends with: TestAdapter.dll TPluginInfo: Microsoft.VisualStudio.TestPlatform.Common.ExtensionFramework.Utilities.TestSettingsProviderPluginInformation TExtension: Microsoft.VisualStudio.TestPlatform.ObjectModel.Adapter.ISettingsProvider +TpTrace Verbose: 0 : 53008, 4, 2026/06/19, 13:41:30.453, 6199779201988, testhost.dll, TestPluginCache.GetExtensionPaths: Filtered extension paths: +TpTrace Verbose: 0 : 53008, 4, 2026/06/19, 13:41:30.454, 6199779202532, testhost.dll, TestPluginCache.GetExtensionPaths: Added default extension paths: D:\Projects\TransactionProcessing\EstateManagementUI\EstateManagementUI.IntegrationTests\bin\Debug\net10.0\NUnit3.TestAdapter.dll +TpTrace Verbose: 0 : 53008, 4, 2026/06/19, 13:41:30.454, 6199779202916, testhost.dll, TestPluginCache.GetExtensionPaths: Added unfilterableExtensionPaths: +TpTrace Information: 0 : 53008, 4, 2026/06/19, 13:41:30.454, 6199779204220, testhost.dll, AssemblyResolver.AddSearchDirectories: Adding more searchDirectories D:\Projects\TransactionProcessing\EstateManagementUI\EstateManagementUI.IntegrationTests\bin\Debug\net10.0 +TpTrace Verbose: 0 : 53008, 4, 2026/06/19, 13:41:30.454, 6199779204887, testhost.dll, TestPluginCache.DiscoverTestExtensions: Discovering the extensions using extension path. +TpTrace Verbose: 0 : 53008, 4, 2026/06/19, 13:41:30.454, 6199779205344, testhost.dll, TestPluginCache.GetExtensionPaths: Filtered extension paths: +TpTrace Verbose: 0 : 53008, 4, 2026/06/19, 13:41:30.454, 6199779205683, testhost.dll, TestPluginCache.GetExtensionPaths: Added default extension paths: D:\Projects\TransactionProcessing\EstateManagementUI\EstateManagementUI.IntegrationTests\bin\Debug\net10.0\NUnit3.TestAdapter.dll +TpTrace Verbose: 0 : 53008, 4, 2026/06/19, 13:41:30.454, 6199779206073, testhost.dll, TestPluginCache.GetExtensionPaths: Added unfilterableExtensionPaths: +TpTrace Verbose: 0 : 53008, 4, 2026/06/19, 13:41:30.454, 6199779206426, testhost.dll, TestPluginCache.DiscoverTestExtensions: Discovering the extensions using allExtensionPaths: D:\Projects\TransactionProcessing\EstateManagementUI\EstateManagementUI.IntegrationTests\bin\Debug\net10.0\NUnit3.TestAdapter.dll +TpTrace Information: 0 : 53008, 4, 2026/06/19, 13:41:30.454, 6199779206981, testhost.dll, AssemblyResolver.AddSearchDirectories: Adding more searchDirectories D:\Projects\TransactionProcessing\EstateManagementUI\EstateManagementUI.IntegrationTests\bin\Debug\net10.0 +TpTrace Verbose: 0 : 53008, 4, 2026/06/19, 13:41:30.454, 6199779207727, testhost.dll, MetadataReaderExtensionsHelper: Discovering extensions inside assembly 'NUnit3.TestAdapter, Version=1.0.0.0, Culture=neutral, PublicKeyToken=4cb40d35494691ac' file path 'D:\Projects\TransactionProcessing\EstateManagementUI\EstateManagementUI.IntegrationTests\bin\Debug\net10.0\NUnit3.TestAdapter.dll' +TpTrace Verbose: 0 : 53008, 4, 2026/06/19, 13:41:30.455, 6199779215526, testhost.dll, TestPluginCache: Discovered the extensions using extension path ''. +TpTrace Verbose: 0 : 53008, 4, 2026/06/19, 13:41:30.455, 6199779216023, testhost.dll, TestPluginCache: Discoverers are ''. +TpTrace Verbose: 0 : 53008, 4, 2026/06/19, 13:41:30.455, 6199779216397, testhost.dll, TestPluginCache: Executors are 'executor://NUnit3TestExecutor'. +TpTrace Verbose: 0 : 53008, 4, 2026/06/19, 13:41:30.455, 6199779216722, testhost.dll, TestPluginCache: Executors2 are ''. +TpTrace Verbose: 0 : 53008, 4, 2026/06/19, 13:41:30.455, 6199779217081, testhost.dll, TestPluginCache: Setting providers are ''. +TpTrace Verbose: 0 : 53008, 4, 2026/06/19, 13:41:30.455, 6199779217356, testhost.dll, TestPluginCache: Loggers are ''. +TpTrace Verbose: 0 : 53008, 4, 2026/06/19, 13:41:30.455, 6199779217597, testhost.dll, TestPluginCache: TestHosts are ''. +TpTrace Verbose: 0 : 53008, 4, 2026/06/19, 13:41:30.455, 6199779217745, testhost.dll, TestPluginCache: DataCollectors are ''. +TpTrace Verbose: 0 : 53008, 4, 2026/06/19, 13:41:30.456, 6199779223183, testhost.dll, TestExecutorService: Loaded the settings providers +TpTrace Information: 0 : 53008, 4, 2026/06/19, 13:41:30.456, 6199779223672, testhost.dll, TestExecutorService: Loaded the extensions +TpTrace Information: 0 : 53008, 4, 2026/06/19, 13:41:30.456, 6199779227883, testhost.dll, TestRequestHandler.OnMessageReceived: Running job 'TestExecution.StartWithSources'. +TpTrace Information: 0 : 53008, 4, 2026/06/19, 13:41:30.520, 6199779863153, testhost.dll, TestDiscoveryManager: Discovering tests from sources D:\Projects\TransactionProcessing\EstateManagementUI\EstateManagementUI.IntegrationTests\bin\Debug\net10.0\EstateManagementUI.IntegrationTests.dll +TpTrace Verbose: 0 : 53008, 4, 2026/06/19, 13:41:30.522, 6199779882163, testhost.dll, TestPluginCache.DiscoverTestExtensions: finding test extensions in assemblies ends with: TestAdapter.dll TPluginInfo: Microsoft.VisualStudio.TestPlatform.Common.ExtensionFramework.Utilities.TestDiscovererPluginInformation TExtension: Microsoft.VisualStudio.TestPlatform.ObjectModel.Adapter.ITestDiscoverer +TpTrace Verbose: 0 : 53008, 4, 2026/06/19, 13:41:30.522, 6199779883615, testhost.dll, TestPluginCache.GetExtensionPaths: Filtered extension paths: +TpTrace Verbose: 0 : 53008, 4, 2026/06/19, 13:41:30.522, 6199779884077, testhost.dll, TestPluginCache.GetExtensionPaths: Added default extension paths: D:\Projects\TransactionProcessing\EstateManagementUI\EstateManagementUI.IntegrationTests\bin\Debug\net10.0\NUnit3.TestAdapter.dll +TpTrace Verbose: 0 : 53008, 4, 2026/06/19, 13:41:30.522, 6199779884378, testhost.dll, TestPluginCache.GetExtensionPaths: Added unfilterableExtensionPaths: +TpTrace Information: 0 : 53008, 4, 2026/06/19, 13:41:30.522, 6199779885436, testhost.dll, AssemblyResolver.AddSearchDirectories: Adding more searchDirectories D:\Projects\TransactionProcessing\EstateManagementUI\EstateManagementUI.IntegrationTests\bin\Debug\net10.0 +TpTrace Verbose: 0 : 53008, 4, 2026/06/19, 13:41:30.522, 6199779885923, testhost.dll, TestPluginCache.DiscoverTestExtensions: Discovering the extensions using extension path. +TpTrace Verbose: 0 : 53008, 4, 2026/06/19, 13:41:30.522, 6199779886234, testhost.dll, TestPluginCache.GetExtensionPaths: Filtered extension paths: +TpTrace Verbose: 0 : 53008, 4, 2026/06/19, 13:41:30.522, 6199779886551, testhost.dll, TestPluginCache.GetExtensionPaths: Added default extension paths: D:\Projects\TransactionProcessing\EstateManagementUI\EstateManagementUI.IntegrationTests\bin\Debug\net10.0\NUnit3.TestAdapter.dll +TpTrace Verbose: 0 : 53008, 4, 2026/06/19, 13:41:30.522, 6199779886790, testhost.dll, TestPluginCache.GetExtensionPaths: Added unfilterableExtensionPaths: +TpTrace Verbose: 0 : 53008, 4, 2026/06/19, 13:41:30.522, 6199779887110, testhost.dll, TestPluginCache.DiscoverTestExtensions: Discovering the extensions using allExtensionPaths: D:\Projects\TransactionProcessing\EstateManagementUI\EstateManagementUI.IntegrationTests\bin\Debug\net10.0\NUnit3.TestAdapter.dll +TpTrace Information: 0 : 53008, 4, 2026/06/19, 13:41:30.522, 6199779887457, testhost.dll, AssemblyResolver.AddSearchDirectories: Adding more searchDirectories D:\Projects\TransactionProcessing\EstateManagementUI\EstateManagementUI.IntegrationTests\bin\Debug\net10.0 +TpTrace Verbose: 0 : 53008, 4, 2026/06/19, 13:41:30.522, 6199779888064, testhost.dll, MetadataReaderExtensionsHelper: Discovering extensions inside assembly 'NUnit3.TestAdapter, Version=1.0.0.0, Culture=neutral, PublicKeyToken=4cb40d35494691ac' file path 'D:\Projects\TransactionProcessing\EstateManagementUI\EstateManagementUI.IntegrationTests\bin\Debug\net10.0\NUnit3.TestAdapter.dll' +TpTrace Information: 0 : 53008, 4, 2026/06/19, 13:41:30.524, 6199779907591, testhost.dll, GetTestExtensionFromType: Register extension with identifier data 'NUnit.VisualStudio.TestAdapter.NUnit3TestDiscoverer, NUnit3.TestAdapter, Version=1.0.0.0, Culture=neutral, PublicKeyToken=4cb40d35494691ac' and type 'NUnit.VisualStudio.TestAdapter.NUnit3TestDiscoverer, NUnit3.TestAdapter, Version=1.0.0.0, Culture=neutral, PublicKeyToken=4cb40d35494691ac' inside file 'D:\Projects\TransactionProcessing\EstateManagementUI\EstateManagementUI.IntegrationTests\bin\Debug\net10.0\NUnit3.TestAdapter.dll' +TpTrace Verbose: 0 : 53008, 4, 2026/06/19, 13:41:30.524, 6199779909684, testhost.dll, TestPluginCache: Discovered the extensions using extension path ''. +TpTrace Verbose: 0 : 53008, 4, 2026/06/19, 13:41:30.524, 6199779910307, testhost.dll, TestPluginCache: Discoverers are 'NUnit.VisualStudio.TestAdapter.NUnit3TestDiscoverer, NUnit3.TestAdapter, Version=1.0.0.0, Culture=neutral, PublicKeyToken=4cb40d35494691ac'. +TpTrace Verbose: 0 : 53008, 4, 2026/06/19, 13:41:30.524, 6199779910546, testhost.dll, TestPluginCache: Executors are 'executor://NUnit3TestExecutor'. +TpTrace Verbose: 0 : 53008, 4, 2026/06/19, 13:41:30.524, 6199779910713, testhost.dll, TestPluginCache: Executors2 are ''. +TpTrace Verbose: 0 : 53008, 4, 2026/06/19, 13:41:30.524, 6199779910857, testhost.dll, TestPluginCache: Setting providers are ''. +TpTrace Verbose: 0 : 53008, 4, 2026/06/19, 13:41:30.524, 6199779910992, testhost.dll, TestPluginCache: Loggers are ''. +TpTrace Verbose: 0 : 53008, 4, 2026/06/19, 13:41:30.524, 6199779911155, testhost.dll, TestPluginCache: TestHosts are ''. +TpTrace Verbose: 0 : 53008, 4, 2026/06/19, 13:41:30.524, 6199779911307, testhost.dll, TestPluginCache: DataCollectors are ''. +TpTrace Information: 0 : 53008, 4, 2026/06/19, 13:41:30.528, 6199779945710, testhost.dll, PEReaderHelper.GetAssemblyType: Determined assemblyType:'Managed' for source: 'D:\Projects\TransactionProcessing\EstateManagementUI\EstateManagementUI.IntegrationTests\bin\Debug\net10.0\EstateManagementUI.IntegrationTests.dll' +TpTrace Verbose: 0 : 53008, 4, 2026/06/19, 13:41:30.548, 6199780148620, testhost.dll, BaseRunTests.RunTestInternalWithExecutors: Running tests for executor://NUnit3TestExecutor +TpTrace Information: 0 : 53008, 4, 2026/06/19, 13:41:30.562, 6199780286891, testhost.dll, AssemblyResolver.OnResolve: nunit.engine: Resolving assembly. +TpTrace Information: 0 : 53008, 4, 2026/06/19, 13:41:30.562, 6199780287993, testhost.dll, AssemblyResolver.OnResolve: nunit.engine: Searching in: 'D:\Projects\TransactionProcessing\EstateManagementUI\EstateManagementUI.IntegrationTests\bin\Debug\net10.0'. +TpTrace Information: 0 : 53008, 4, 2026/06/19, 13:41:30.562, 6199780290587, testhost.dll, AssemblyResolver.OnResolve: nunit.engine: Loading assembly 'D:\Projects\TransactionProcessing\EstateManagementUI\EstateManagementUI.IntegrationTests\bin\Debug\net10.0\nunit.engine.dll'. +TpTrace Information: 0 : 53008, 4, 2026/06/19, 13:41:30.563, 6199780293985, testhost.dll, AssemblyResolver.OnResolve: Resolved assembly: nunit.engine, from path: D:\Projects\TransactionProcessing\EstateManagementUI\EstateManagementUI.IntegrationTests\bin\Debug\net10.0\nunit.engine.dll +TpTrace Information: 0 : 53008, 4, 2026/06/19, 13:41:30.563, 6199780294746, testhost.dll, AssemblyResolver.OnResolve: nunit.engine.core: Resolving assembly. +TpTrace Information: 0 : 53008, 4, 2026/06/19, 13:41:30.563, 6199780295128, testhost.dll, AssemblyResolver.OnResolve: nunit.engine.core: Searching in: 'D:\Projects\TransactionProcessing\EstateManagementUI\EstateManagementUI.IntegrationTests\bin\Debug\net10.0'. +TpTrace Information: 0 : 53008, 4, 2026/06/19, 13:41:30.563, 6199780297187, testhost.dll, AssemblyResolver.OnResolve: nunit.engine.core: Loading assembly 'D:\Projects\TransactionProcessing\EstateManagementUI\EstateManagementUI.IntegrationTests\bin\Debug\net10.0\nunit.engine.core.dll'. +TpTrace Information: 0 : 53008, 4, 2026/06/19, 13:41:30.563, 6199780300192, testhost.dll, AssemblyResolver.OnResolve: Resolved assembly: nunit.engine.core, from path: D:\Projects\TransactionProcessing\EstateManagementUI\EstateManagementUI.IntegrationTests\bin\Debug\net10.0\nunit.engine.core.dll +TpTrace Information: 0 : 53008, 4, 2026/06/19, 13:41:30.570, 6199780362230, testhost.dll, NUnit Adapter 1.0.0.0: Test execution started +TpTrace Verbose: 0 : 53008, 4, 2026/06/19, 13:41:30.570, 6199780363589, testhost.dll, TestRequestHandler.SendData: sending data from testhost: {"Version":7,"MessageType":"TestSession.Message","Payload":{"MessageLevel":0,"Message":"NUnit Adapter 1.0.0.0: Test execution started"}} +TpTrace Verbose: 0 : 53008, 4, 2026/06/19, 13:41:30.570, 6199780365575, testhost.dll, MulticastDelegateUtilities.SafeInvoke: TestRunMessageLoggerProxy.SendMessage: Invoking callback 1/1 for Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.Execution.RunTestsWithSources., took 0 ms. +TpTrace Information: 0 : 53008, 4, 2026/06/19, 13:41:30.606, 6199780727924, testhost.dll, Running selected tests in D:\Projects\TransactionProcessing\EstateManagementUI\EstateManagementUI.IntegrationTests\bin\Debug\net10.0\EstateManagementUI.IntegrationTests.dll +TpTrace Verbose: 0 : 53008, 4, 2026/06/19, 13:41:30.606, 6199780729291, testhost.dll, TestRequestHandler.SendData: sending data from testhost: {"Version":7,"MessageType":"TestSession.Message","Payload":{"MessageLevel":0,"Message":"Running selected tests in D:\\Projects\\TransactionProcessing\\EstateManagementUI\\EstateManagementUI.IntegrationTests\\bin\\Debug\\net10.0\\EstateManagementUI.IntegrationTests.dll"}} +TpTrace Verbose: 0 : 53008, 4, 2026/06/19, 13:41:30.606, 6199780730417, testhost.dll, MulticastDelegateUtilities.SafeInvoke: TestRunMessageLoggerProxy.SendMessage: Invoking callback 1/1 for Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.Execution.RunTestsWithSources., took 0 ms. +TpTrace Information: 0 : 53008, 4, 2026/06/19, 13:41:30.617, 6199780836198, testhost.dll, AssemblyResolver.OnResolve: testcentric.engine.metadata: Resolving assembly. +TpTrace Information: 0 : 53008, 4, 2026/06/19, 13:41:30.617, 6199780837144, testhost.dll, AssemblyResolver.OnResolve: testcentric.engine.metadata: Searching in: 'D:\Projects\TransactionProcessing\EstateManagementUI\EstateManagementUI.IntegrationTests\bin\Debug\net10.0'. +TpTrace Information: 0 : 53008, 4, 2026/06/19, 13:41:30.617, 6199780839411, testhost.dll, AssemblyResolver.OnResolve: testcentric.engine.metadata: Loading assembly 'D:\Projects\TransactionProcessing\EstateManagementUI\EstateManagementUI.IntegrationTests\bin\Debug\net10.0\testcentric.engine.metadata.dll'. +TpTrace Information: 0 : 53008, 4, 2026/06/19, 13:41:30.618, 6199780842537, testhost.dll, AssemblyResolver.OnResolve: Resolved assembly: testcentric.engine.metadata, from path: D:\Projects\TransactionProcessing\EstateManagementUI\EstateManagementUI.IntegrationTests\bin\Debug\net10.0\testcentric.engine.metadata.dll +TpTrace Information: 0 : 53008, 4, 2026/06/19, 13:41:30.812, 6199782782676, testhost.dll, NUnit3TestExecutor discovered 1 of 1 NUnit test cases using Current Discovery mode, Non-Explicit run +TpTrace Verbose: 0 : 53008, 4, 2026/06/19, 13:41:30.812, 6199782783922, testhost.dll, TestRequestHandler.SendData: sending data from testhost: {"Version":7,"MessageType":"TestSession.Message","Payload":{"MessageLevel":0,"Message":" NUnit3TestExecutor discovered 1 of 1 NUnit test cases using Current Discovery mode, Non-Explicit run"}} +TpTrace Verbose: 0 : 53008, 4, 2026/06/19, 13:41:30.812, 6199782785357, testhost.dll, MulticastDelegateUtilities.SafeInvoke: TestRunMessageLoggerProxy.SendMessage: Invoking callback 1/1 for Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.Execution.RunTestsWithSources., took 0 ms. +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:41:31.419, 6199788861527, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1007 ms +TpTrace Verbose: 0 : 53008, 13, 2026/06/19, 13:41:32.121, 6199795879111, testhost.dll, TestExecutionRecorder.RecordStart: Starting test: EstateManagementUI.IntegrationTests.Features.DashboardFeature.AdministratorsSeeTheDashboardWelcomePanel. +TpTrace Information: 0 : 53008, 13, 2026/06/19, 13:41:32.123, 6199795898966, testhost.dll, Sending test run statistics +TpTrace Verbose: 0 : 53008, 13, 2026/06/19, 13:41:32.147, 6199796132684, testhost.dll, TestRequestHandler.SendData: sending data from testhost: {"Version":7,"MessageType":"TestExecution.StatsChange","Payload":{"NewTestResults":[],"TestRunStatistics":{"ExecutedTests":0,"Stats":{}},"ActiveTests":[{"Id":"856509a0-37bf-5299-e232-e80e305d4dd4","FullyQualifiedName":"EstateManagementUI.IntegrationTests.Features.DashboardFeature.AdministratorsSeeTheDashboardWelcomePanel","DisplayName":"AdministratorsSeeTheDashboardWelcomePanel","ExecutorUri":"executor://NUnit3TestExecutor","Source":"D:\\Projects\\TransactionProcessing\\EstateManagementUI\\EstateManagementUI.IntegrationTests\\bin\\Debug\\net10.0\\EstateManagementUI.IntegrationTests.dll","CodeFilePath":null,"LineNumber":0,"Properties":[{"Key":{"Id":"NUnit.TestCategory","Label":"TestCategory","Category":"","Description":"","Attributes":5,"ValueType":"System.String[]"},"Value":["base","background","dashboard","Dashboard","AdministratorRole"]},{"Key":{"Id":"NUnit.Seed","Label":"Seed","Category":"","Description":"","Attributes":0,"ValueType":"System.String"},"Value":"1743199602"}]}]}} +TpTrace Verbose: 0 : 53008, 13, 2026/06/19, 13:41:32.147, 6199796134744, testhost.dll, TestRunCache: OnNewTestResult: Notified the onCacheHit callback. +TpTrace Information: 0 : 53008, 19, 2026/06/19, 13:41:32.301, 6199797674608, testhost.dll, AssemblyResolver.OnResolve: SimpleResults.resources: Resolving assembly. +TpTrace Information: 0 : 53008, 19, 2026/06/19, 13:41:32.301, 6199797675991, testhost.dll, AssemblyResolver.OnResolve: SimpleResults.resources: Searching in: 'D:\Projects\TransactionProcessing\EstateManagementUI\EstateManagementUI.IntegrationTests\bin\Debug\net10.0'. +TpTrace Information: 0 : 53008, 19, 2026/06/19, 13:41:32.301, 6199797677468, testhost.dll, AssemblyResolver.OnResolve: SimpleResults.resources: Assembly path does not exist: 'D:\Projects\TransactionProcessing\EstateManagementUI\EstateManagementUI.IntegrationTests\bin\Debug\net10.0\SimpleResults.resources.dll', returning. +TpTrace Information: 0 : 53008, 19, 2026/06/19, 13:41:32.301, 6199797678547, testhost.dll, AssemblyResolver.OnResolve: SimpleResults.resources: Assembly path does not exist: 'D:\Projects\TransactionProcessing\EstateManagementUI\EstateManagementUI.IntegrationTests\bin\Debug\net10.0\SimpleResults.resources.exe', returning. +TpTrace Information: 0 : 53008, 19, 2026/06/19, 13:41:32.301, 6199797678775, testhost.dll, AssemblyResolver.OnResolve: SimpleResults.resources: Failed to load assembly. +TpTrace Information: 0 : 53008, 19, 2026/06/19, 13:41:32.363, 6199798297752, testhost.dll, AssemblyResolver.OnResolve: SimpleResults.resources: Resolving assembly. +TpTrace Information: 0 : 53008, 19, 2026/06/19, 13:41:32.363, 6199798298816, testhost.dll, AssemblyResolver.OnResolve: SimpleResults.resources: Resolved from cache. +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:41:32.430, 6199798967781, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1010 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:41:33.443, 6199809092865, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1012 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:41:34.452, 6199819187698, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1009 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:41:35.467, 6199829337189, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1014 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:41:36.469, 6199839358143, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1001 ms +TpTrace Information: 0 : 53008, 20, 2026/06/19, 13:41:36.685, 6199841518438, testhost.dll, AssemblyResolver.OnResolve: Microsoft.Data.SqlClient.resources: Resolving assembly. +TpTrace Information: 0 : 53008, 20, 2026/06/19, 13:41:36.685, 6199841519474, testhost.dll, AssemblyResolver.OnResolve: Microsoft.Data.SqlClient.resources: Searching in: 'D:\Projects\TransactionProcessing\EstateManagementUI\EstateManagementUI.IntegrationTests\bin\Debug\net10.0'. +TpTrace Information: 0 : 53008, 20, 2026/06/19, 13:41:36.685, 6199841520589, testhost.dll, AssemblyResolver.OnResolve: Microsoft.Data.SqlClient.resources: Assembly path does not exist: 'D:\Projects\TransactionProcessing\EstateManagementUI\EstateManagementUI.IntegrationTests\bin\Debug\net10.0\Microsoft.Data.SqlClient.resources.dll', returning. +TpTrace Information: 0 : 53008, 20, 2026/06/19, 13:41:36.685, 6199841521825, testhost.dll, AssemblyResolver.OnResolve: Microsoft.Data.SqlClient.resources: Assembly path does not exist: 'D:\Projects\TransactionProcessing\EstateManagementUI\EstateManagementUI.IntegrationTests\bin\Debug\net10.0\Microsoft.Data.SqlClient.resources.exe', returning. +TpTrace Information: 0 : 53008, 20, 2026/06/19, 13:41:36.686, 6199841522288, testhost.dll, AssemblyResolver.OnResolve: Microsoft.Data.SqlClient.resources: Failed to load assembly. +TpTrace Information: 0 : 53008, 20, 2026/06/19, 13:41:36.702, 6199841689278, testhost.dll, AssemblyResolver.OnResolve: Microsoft.Data.SqlClient.resources: Resolving assembly. +TpTrace Information: 0 : 53008, 20, 2026/06/19, 13:41:36.702, 6199841690466, testhost.dll, AssemblyResolver.OnResolve: Microsoft.Data.SqlClient.resources: Resolved from cache. +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:41:37.475, 6199849420887, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1006 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:41:38.485, 6199859512437, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1008 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:41:39.490, 6199869563706, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1004 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:41:40.499, 6199879655803, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1009 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:41:41.511, 6199889778544, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1012 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:41:42.520, 6199899869803, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1008 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:41:43.528, 6199909947573, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1007 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:41:44.535, 6199920018972, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1006 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:41:45.544, 6199930109297, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1008 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:41:46.545, 6199940116235, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1000 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:41:47.550, 6199950165310, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1004 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:41:48.558, 6199960246323, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1007 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:41:49.565, 6199970318962, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1007 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:41:50.569, 6199980361239, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1004 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:41:51.583, 6199990500672, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1013 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:41:52.587, 6200000535551, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1003 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:41:53.597, 6200010640107, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1010 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:41:54.610, 6200020767320, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1012 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:41:55.614, 6200030810288, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1004 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:41:56.616, 6200040824964, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1001 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:41:57.625, 6200050915885, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1008 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:41:58.628, 6200060943237, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1002 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:41:59.636, 6200071023672, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1007 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:42:00.641, 6200081081420, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1005 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:42:01.655, 6200091221846, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1013 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:42:02.668, 6200101346689, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1012 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:42:03.670, 6200111364691, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1001 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:42:04.673, 6200121396116, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1003 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:42:05.676, 6200131428919, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1003 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:42:06.691, 6200141577395, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1014 ms +TpTrace Information: 0 : 53008, 20, 2026/06/19, 13:42:07.096, 6200145622078, testhost.dll, AssemblyResolver.OnResolve: System.Net.Sockets.resources: Resolving assembly. +TpTrace Information: 0 : 53008, 20, 2026/06/19, 13:42:07.096, 6200145622959, testhost.dll, AssemblyResolver.OnResolve: System.Net.Sockets.resources: Searching in: 'D:\Projects\TransactionProcessing\EstateManagementUI\EstateManagementUI.IntegrationTests\bin\Debug\net10.0'. +TpTrace Information: 0 : 53008, 20, 2026/06/19, 13:42:07.096, 6200145626307, testhost.dll, AssemblyResolver.OnResolve: System.Net.Sockets.resources: Assembly path does not exist: 'D:\Projects\TransactionProcessing\EstateManagementUI\EstateManagementUI.IntegrationTests\bin\Debug\net10.0\System.Net.Sockets.resources.dll', returning. +TpTrace Information: 0 : 53008, 20, 2026/06/19, 13:42:07.096, 6200145627576, testhost.dll, AssemblyResolver.OnResolve: System.Net.Sockets.resources: Assembly path does not exist: 'D:\Projects\TransactionProcessing\EstateManagementUI\EstateManagementUI.IntegrationTests\bin\Debug\net10.0\System.Net.Sockets.resources.exe', returning. +TpTrace Information: 0 : 53008, 20, 2026/06/19, 13:42:07.096, 6200145628031, testhost.dll, AssemblyResolver.OnResolve: System.Net.Sockets.resources: Failed to load assembly. +TpTrace Information: 0 : 53008, 20, 2026/06/19, 13:42:07.107, 6200145735292, testhost.dll, AssemblyResolver.OnResolve: System.Net.Sockets.resources: Resolving assembly. +TpTrace Information: 0 : 53008, 20, 2026/06/19, 13:42:07.107, 6200145736048, testhost.dll, AssemblyResolver.OnResolve: System.Net.Sockets.resources: Resolved from cache. +TpTrace Information: 0 : 53008, 20, 2026/06/19, 13:42:07.119, 6200145852977, testhost.dll, AssemblyResolver.OnResolve: System.Net.Http.resources: Resolving assembly. +TpTrace Information: 0 : 53008, 20, 2026/06/19, 13:42:07.119, 6200145853570, testhost.dll, AssemblyResolver.OnResolve: System.Net.Http.resources: Searching in: 'D:\Projects\TransactionProcessing\EstateManagementUI\EstateManagementUI.IntegrationTests\bin\Debug\net10.0'. +TpTrace Information: 0 : 53008, 20, 2026/06/19, 13:42:07.119, 6200145854605, testhost.dll, AssemblyResolver.OnResolve: System.Net.Http.resources: Assembly path does not exist: 'D:\Projects\TransactionProcessing\EstateManagementUI\EstateManagementUI.IntegrationTests\bin\Debug\net10.0\System.Net.Http.resources.dll', returning. +TpTrace Information: 0 : 53008, 20, 2026/06/19, 13:42:07.119, 6200145856832, testhost.dll, AssemblyResolver.OnResolve: System.Net.Http.resources: Assembly path does not exist: 'D:\Projects\TransactionProcessing\EstateManagementUI\EstateManagementUI.IntegrationTests\bin\Debug\net10.0\System.Net.Http.resources.exe', returning. +TpTrace Information: 0 : 53008, 20, 2026/06/19, 13:42:07.119, 6200145858107, testhost.dll, AssemblyResolver.OnResolve: System.Net.Http.resources: Failed to load assembly. +TpTrace Information: 0 : 53008, 20, 2026/06/19, 13:42:07.130, 6200145967382, testhost.dll, AssemblyResolver.OnResolve: System.Net.Http.resources: Resolving assembly. +TpTrace Information: 0 : 53008, 20, 2026/06/19, 13:42:07.130, 6200145967941, testhost.dll, AssemblyResolver.OnResolve: System.Net.Http.resources: Resolved from cache. +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:42:07.698, 6200151648858, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1007 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:42:08.710, 6200161766623, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1011 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:42:09.717, 6200171836046, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1006 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:42:10.718, 6200181845072, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1000 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:42:11.721, 6200191875330, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1002 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:42:12.728, 6200201947068, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1007 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:42:13.738, 6200212050509, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1010 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:42:14.745, 6200222112982, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1006 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:42:15.751, 6200232175435, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1006 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:42:16.765, 6200242318282, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1014 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:42:17.770, 6200252364635, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1004 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:42:18.777, 6200262436846, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1007 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:42:19.788, 6200272546110, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1010 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:42:20.791, 6200282579675, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1003 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:42:21.795, 6200292612018, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1003 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:42:22.795, 6200302618358, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1000 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:42:23.810, 6200312764989, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1014 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:42:24.821, 6200322880665, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1011 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:42:25.836, 6200333025547, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1014 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:42:26.838, 6200343043889, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1001 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:42:27.848, 6200353145402, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1009 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:42:28.860, 6200363266432, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1011 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:42:29.862, 6200373291669, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1002 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:42:30.865, 6200383318356, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1002 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:42:31.880, 6200393465641, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1014 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:42:32.888, 6200403545975, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1007 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:42:33.903, 6200413692129, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1014 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:42:34.912, 6200423783844, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1009 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:42:35.922, 6200433885728, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1010 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:42:36.928, 6200443944810, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1005 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:42:37.932, 6200453984400, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1003 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:42:38.934, 6200464004835, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1001 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:42:39.934, 6200474010070, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1000 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:42:40.938, 6200484050679, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1003 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:42:41.949, 6200494157866, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1010 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:42:42.954, 6200504206783, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1004 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:42:43.957, 6200514238252, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1003 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:42:44.962, 6200524291804, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1005 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:42:45.966, 6200534326162, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1003 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:42:46.968, 6200544346373, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1001 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:42:47.979, 6200554459427, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1011 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:42:48.984, 6200564509736, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1004 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:42:49.993, 6200574593690, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1008 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:42:50.999, 6200584654421, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1005 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:42:52.005, 6200594714049, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1005 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:42:53.020, 6200604862298, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1014 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:42:54.033, 6200614993614, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1013 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:42:55.042, 6200625084163, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1008 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:42:56.052, 6200635190821, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1010 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:42:57.067, 6200645333021, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1014 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:42:58.067, 6200655339744, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1000 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:42:59.079, 6200665458230, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1011 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:43:00.087, 6200675532971, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1007 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:43:01.097, 6200685636001, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1010 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:43:02.106, 6200695723721, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1008 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:43:03.121, 6200705873009, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1014 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:43:04.130, 6200715964751, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1009 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:43:05.142, 6200726085936, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1012 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:43:06.155, 6200736215392, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1012 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:43:07.157, 6200746239133, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1002 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:43:08.165, 6200756319952, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1007 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:43:09.173, 6200766394875, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1007 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:43:10.179, 6200776456845, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1006 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:43:11.188, 6200786546861, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1008 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:43:12.198, 6200796647587, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1009 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:43:13.212, 6200806789660, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1014 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:43:14.218, 6200816844826, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1005 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:43:15.226, 6200826928218, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1008 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:43:16.236, 6200837022463, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1009 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:43:17.240, 6200847069780, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1004 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:43:18.244, 6200857106329, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1003 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:43:19.250, 6200867164763, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1005 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:43:20.251, 6200877172672, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1000 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:43:21.265, 6200887315185, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1014 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:43:22.272, 6200897387926, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1007 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:43:23.280, 6200907463559, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1007 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:43:24.286, 6200917530571, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1006 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:43:25.300, 6200927664028, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1013 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:43:26.311, 6200937780091, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1011 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:43:27.324, 6200947904937, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1012 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:43:28.330, 6200957964225, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1005 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:43:29.344, 6200968111238, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1014 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:43:30.360, 6200978266274, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1015 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:43:31.373, 6200988401202, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1013 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:43:32.385, 6200998512330, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1010 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:43:33.386, 6201008531776, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1001 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:43:34.398, 6201018642223, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1010 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:43:35.407, 6201028732177, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1008 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:43:36.418, 6201038847011, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1011 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:43:37.428, 6201048944220, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1009 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:43:38.442, 6201059087824, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1014 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:43:39.455, 6201069212780, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1012 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:43:40.466, 6201079328668, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1011 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:43:41.476, 6201089430153, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1010 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:43:42.486, 6201099528975, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1009 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:43:43.491, 6201109573480, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1004 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:43:44.509, 6201119756453, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1005 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:43:45.514, 6201129805985, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1004 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:43:46.526, 6201139922547, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1011 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:43:47.528, 6201149947851, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1002 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:43:48.528, 6201159947982, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 999 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:43:49.542, 6201170089256, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1014 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:43:50.548, 6201180146596, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1005 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:43:51.558, 6201190250638, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1010 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:43:52.565, 6201200312737, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1006 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:43:53.573, 6201210394931, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1008 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:43:54.584, 6201220507106, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1011 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:43:55.588, 6201230545267, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1003 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:43:56.600, 6201240671493, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1012 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:43:57.612, 6201250786918, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1011 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:43:58.617, 6201260833207, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1004 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:43:59.629, 6201270954539, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1012 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:44:00.630, 6201280964333, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1000 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:44:01.639, 6201291054838, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1008 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:44:02.641, 6201301073296, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1001 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:44:03.655, 6201311220822, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1014 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:44:04.669, 6201321355833, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1013 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:44:05.683, 6201331496877, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1013 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:44:06.692, 6201341588607, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1009 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:44:07.693, 6201351596901, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1000 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:44:08.696, 6201361629306, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1003 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:44:09.709, 6201371761063, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1013 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:44:10.710, 6201381766416, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1000 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:44:11.715, 6201391817471, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1005 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:44:12.721, 6201401881546, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1006 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:44:13.736, 6201412022098, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1013 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:44:14.738, 6201422046452, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1002 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:44:15.743, 6201432100368, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1005 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:44:16.745, 6201442113903, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1001 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:44:17.758, 6201452250952, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1013 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:44:18.772, 6201462391327, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1013 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:44:19.785, 6201472518409, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1012 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:44:20.793, 6201482596778, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1007 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:44:21.806, 6201492729345, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1013 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:44:22.816, 6201502824513, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1009 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:44:23.816, 6201512831305, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1000 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:44:24.823, 6201522893624, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1006 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:44:25.832, 6201532991454, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1009 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:44:26.844, 6201543106387, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1011 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:44:27.848, 6201553143676, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1003 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:44:28.850, 6201563168798, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1002 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:44:29.865, 6201573316935, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1014 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:44:30.869, 6201583358647, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1004 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:44:31.880, 6201593466136, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1010 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:44:32.887, 6201603541705, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1007 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:44:33.896, 6201613631293, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1008 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:44:34.908, 6201623750697, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1011 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:44:35.915, 6201633821677, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1006 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:44:36.916, 6201643826098, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1000 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:44:37.916, 6201653830278, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1000 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:44:38.922, 6201663888528, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1005 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:44:39.925, 6201673920185, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1003 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:44:40.937, 6201684038692, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1011 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:44:41.944, 6201694103099, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1006 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:44:42.944, 6201704107283, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1000 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:44:43.954, 6201714204207, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1009 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:44:44.965, 6201724321989, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1011 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:44:45.970, 6201734367290, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1004 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:44:46.978, 6201744444973, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1007 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:44:47.985, 6201754519614, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1007 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:44:48.993, 6201764600061, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1007 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:44:49.999, 6201774659148, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1005 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:44:51.004, 6201784703997, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1004 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:44:52.015, 6201794815751, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1011 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:44:53.024, 6201804902245, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1008 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:44:54.028, 6201814944537, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1004 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:44:55.033, 6201825000115, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1005 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:44:56.040, 6201835065625, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1006 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:44:57.046, 6201845129591, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1006 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:44:58.051, 6201855178842, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1004 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:44:59.052, 6201865182346, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1000 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:45:00.060, 6201875268309, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1008 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:45:01.073, 6201885392239, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1012 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:45:02.080, 6201895469113, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1007 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:45:03.086, 6201905525909, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1005 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:45:04.095, 6201915612576, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1008 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:45:05.098, 6201925647195, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1003 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:45:06.108, 6201935743721, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1009 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:45:07.116, 6201945827294, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1008 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:45:08.130, 6201955962475, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1013 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:45:09.130, 6201965965936, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1000 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:45:10.132, 6201975982471, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1001 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:45:11.142, 6201986090161, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1010 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:45:12.154, 6201996208543, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1011 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:45:13.160, 6202006263298, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1005 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:45:14.168, 6202016344777, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1008 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:45:15.169, 6202026359552, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1001 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:45:16.174, 6202036406582, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1004 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:45:17.177, 6202046439748, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1003 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:45:18.178, 6202056446180, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1000 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:45:19.184, 6202066502018, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1005 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:45:20.192, 6202076583711, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1008 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:45:21.196, 6202086623837, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1003 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:45:22.199, 6202096659602, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1003 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:45:23.209, 6202106760030, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1009 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:45:24.217, 6202116840294, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1007 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:45:25.222, 6202126885778, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1004 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:45:26.236, 6202137028050, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1014 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:45:27.251, 6202147172914, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1014 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:45:28.264, 6202157306089, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1013 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:45:29.269, 6202167352138, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1004 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:45:30.280, 6202177471421, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1011 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:45:31.294, 6202187610644, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1013 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:45:32.305, 6202197716567, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1010 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:45:33.320, 6202207869686, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1015 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:45:34.335, 6202218018769, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1014 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:45:35.344, 6202228108578, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1008 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:45:36.358, 6202238245716, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1013 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:45:37.370, 6202248369260, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1012 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:45:38.376, 6202258426487, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1005 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:45:39.377, 6202268440669, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1001 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:45:40.390, 6202278565435, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1012 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:45:41.392, 6202288591031, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1002 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:45:42.395, 6202298619500, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1002 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:45:43.408, 6202308748668, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1012 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:45:44.419, 6202318861163, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1011 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:45:45.420, 6202328869418, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1000 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:45:46.434, 6202339007510, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1013 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:45:47.444, 6202349104957, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1009 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:45:48.448, 6202359145703, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1003 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:45:49.460, 6202369270671, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1012 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:45:50.476, 6202379423883, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1015 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:45:51.484, 6202389504983, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1007 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:45:52.496, 6202399625852, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1011 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:45:53.500, 6202409671004, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1004 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:45:54.506, 6202419724899, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1005 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:45:55.506, 6202429724612, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 999 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:45:56.509, 6202439754633, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1002 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:45:57.516, 6202449825680, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1007 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:45:58.523, 6202459893426, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1006 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:45:59.538, 6202470042505, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1014 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:46:00.538, 6202480049518, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1000 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:46:01.546, 6202490125962, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1007 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:46:02.548, 6202500150803, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1002 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:46:03.561, 6202510279851, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1012 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:46:04.568, 6202520350857, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1006 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:46:05.581, 6202530473597, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1012 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:46:06.589, 6202540556573, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1008 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:46:07.599, 6202550656895, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1009 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:46:08.605, 6202560718466, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1006 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:46:09.615, 6202570816181, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1009 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:46:10.623, 6202580894744, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1007 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:46:11.634, 6202591010583, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1011 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:46:12.647, 6202601136216, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1012 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:46:13.655, 6202611221473, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1008 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:46:14.663, 6202621296903, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1007 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:46:15.671, 6202631374325, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1007 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:46:16.681, 6202641475737, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1010 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:46:17.692, 6202651591807, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1011 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:46:18.698, 6202661645614, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1005 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:46:19.713, 6202671792207, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1014 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:46:20.727, 6202681940771, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1014 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:46:21.742, 6202692091960, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1014 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:46:22.756, 6202702225143, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1013 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:46:23.759, 6202712257482, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1003 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:46:24.773, 6202722399364, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1014 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:46:25.785, 6202732521347, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1012 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:46:26.796, 6202742623642, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1010 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:46:27.808, 6202752750909, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1012 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:46:28.816, 6202762825454, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1007 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:46:29.830, 6202772962809, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1013 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:46:30.834, 6202783008750, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1004 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:46:31.848, 6202793148191, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1013 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:46:32.851, 6202803178829, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1002 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:46:33.863, 6202813298518, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1011 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:46:34.875, 6202823417558, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1011 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:46:35.881, 6202833474686, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1005 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:46:36.883, 6202843497933, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1002 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:46:37.891, 6202853581887, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1008 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:46:38.896, 6202863631359, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1004 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:46:39.902, 6202873687975, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1005 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:46:40.904, 6202883704931, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1001 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:46:41.910, 6202893763597, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1005 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:46:42.921, 6202903876827, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1011 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:46:43.928, 6202913949094, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1007 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:46:44.935, 6202924017683, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1006 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:46:45.949, 6202934156919, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1013 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:46:46.954, 6202944209564, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1005 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:46:47.964, 6202954304865, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1009 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:46:48.976, 6202964427834, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1012 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:46:49.985, 6202974512669, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1008 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:46:50.992, 6202984588586, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1007 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:46:52.000, 6202994668875, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1007 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:46:53.007, 6203004739232, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1006 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:46:54.010, 6203014763300, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1002 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:46:55.020, 6203024864351, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1009 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:46:56.023, 6203034896840, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1003 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:46:57.038, 6203045042828, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1014 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:46:58.041, 6203055073159, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1002 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:46:59.044, 6203065105812, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1003 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:47:00.054, 6203075203590, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1009 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:47:01.057, 6203085236378, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1003 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:47:02.072, 6203095384711, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1014 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:47:03.082, 6203105489527, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1010 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:47:04.094, 6203115610819, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1012 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:47:05.108, 6203125746273, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1013 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:47:06.115, 6203135815827, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1006 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:47:07.118, 6203145846948, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1002 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:47:08.125, 6203155915088, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1006 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:47:09.138, 6203166048605, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1013 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:47:10.139, 6203176055230, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1000 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:47:11.146, 6203186125237, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1006 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:47:12.160, 6203196271861, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1014 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:47:13.165, 6203206315530, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1004 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:47:14.170, 6203216364638, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1004 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:47:15.184, 6203226508930, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1014 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:47:16.196, 6203236627201, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1011 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:47:17.206, 6203246723739, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1009 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:47:18.215, 6203256820615, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1009 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:47:19.224, 6203266908616, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1008 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:47:20.232, 6203276989813, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1008 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:47:21.240, 6203287065167, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1007 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:47:22.254, 6203297202023, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1013 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:47:23.265, 6203307317507, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1011 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:47:24.275, 6203317416353, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1009 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:47:25.284, 6203327503265, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1008 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:47:26.291, 6203337573471, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1006 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:47:27.296, 6203347627899, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1005 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:47:28.310, 6203357765321, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1013 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:47:29.324, 6203367904481, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1013 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:47:30.328, 6203377950438, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1004 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:47:31.333, 6203387998839, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1004 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:47:32.342, 6203398084312, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1008 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:47:33.350, 6203408170055, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1008 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:47:34.358, 6203418251907, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1008 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:47:35.371, 6203428380579, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1012 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:47:36.385, 6203438519497, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1013 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:47:37.389, 6203448561568, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1004 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:47:38.404, 6203458711136, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1014 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:47:39.420, 6203468865356, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1015 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:47:40.433, 6203479001168, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1013 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:47:41.438, 6203489044395, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1004 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:47:42.450, 6203499169377, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1012 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:47:43.454, 6203509207121, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1003 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:47:44.455, 6203519221079, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1001 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:47:45.458, 6203529244342, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1002 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:47:46.460, 6203539267344, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1002 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:47:47.465, 6203549318516, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1005 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:47:48.469, 6203559352288, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1003 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:47:49.469, 6203569362005, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1000 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:47:50.473, 6203579400163, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1003 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:47:51.475, 6203589415528, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1001 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:47:52.488, 6203599550596, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1013 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:47:53.500, 6203609662194, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1011 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:47:54.509, 6203619758474, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1009 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:47:55.514, 6203629810364, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1004 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:47:56.529, 6203639959073, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1014 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:47:57.537, 6203650035671, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1007 ms +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:47:58.538, 6203660048845, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1001 ms +TpTrace Information: 0 : 53008, 13, 2026/06/19, 13:47:58.787, 6203662538305, testhost.dll, [testcontainers.org 00:00:00.06] Connected to Docker: + Host: npipe://./pipe/docker_engine + Server Version: 29.4.3 + Kernel Version: 6.12.76-linuxkit + API Version: 1.54 + Operating System: Docker Desktop + Total Memory: 3.82 GB + Labels: + com.docker.desktop.address=npipe://\\.\pipe\docker_cli +[testcontainers.org 00:00:00.13] Docker network ab5c7ec2ca97 created +[testcontainers.org 00:00:00.40] Docker container bb704f0c4c72 created +[testcontainers.org 00:00:00.46] Start Docker container bb704f0c4c72 +[testcontainers.org 00:00:00.72] Wait for Docker container bb704f0c4c72 to complete readiness checks +[testcontainers.org 00:00:01.79] Docker container bb704f0c4c72 ready +[testcontainers.org 00:00:01.90] Docker container 80cc17022ab1 created +[testcontainers.org 00:00:01.91] Start Docker container 80cc17022ab1 +[testcontainers.org 00:00:03.92] Wait for Docker container 80cc17022ab1 to complete readiness checks +[testcontainers.org 00:00:03.93] Docker container 80cc17022ab1 ready +[testcontainers.org 00:00:34.37] Docker container 1df1fd9fb44e created +[testcontainers.org 00:00:34.38] Start Docker container 1df1fd9fb44e +[testcontainers.org 00:00:34.58] Wait for Docker container 1df1fd9fb44e to complete readiness checks +[testcontainers.org 00:00:34.59] Docker container 1df1fd9fb44e ready +[testcontainers.org 00:01:34.74] Docker container 7752202c2996 created +[testcontainers.org 00:01:34.75] Start Docker container 7752202c2996 +[testcontainers.org 00:01:34.99] Wait for Docker container 7752202c2996 to complete readiness checks +[testcontainers.org 00:01:35.00] Docker container 7752202c2996 ready +About to Start Security Container +[testcontainers.org 00:03:55.58] Docker container e7bbcc0242ca created +[testcontainers.org 00:03:55.59] Start Docker container e7bbcc0242ca +[testcontainers.org 00:03:55.87] Wait for Docker container e7bbcc0242ca to complete readiness checks +[testcontainers.org 00:03:55.87] Docker container e7bbcc0242ca ready +[testcontainers.org 00:04:21.97] Docker container 0ead7ba827ae created +[testcontainers.org 00:04:21.98] Start Docker container 0ead7ba827ae +[testcontainers.org 00:04:22.32] Wait for Docker container 0ead7ba827ae to complete readiness checks +[testcontainers.org 00:04:22.33] Docker container 0ead7ba827ae ready +[testcontainers.org 00:04:43.73] Docker container 54b1d3f6190d created +[testcontainers.org 00:04:43.77] Start Docker container 54b1d3f6190d +[testcontainers.org 00:04:44.66] Wait for Docker container 54b1d3f6190d to complete readiness checks +[testcontainers.org 00:04:44.70] Docker container 54b1d3f6190d ready +[testcontainers.org 00:05:05.18] Docker container 7c75f5814a9d created +[testcontainers.org 00:05:05.19] Start Docker container 7c75f5814a9d +[testcontainers.org 00:05:05.45] Wait for Docker container 7c75f5814a9d to complete readiness checks +[testcontainers.org 00:05:05.46] Docker container 7c75f5814a9d ready +[testcontainers.org 00:05:26.34] Docker container 40d813ea0972 created +[testcontainers.org 00:05:26.38] Start Docker container 40d813ea0972 +[testcontainers.org 00:05:26.96] Wait for Docker container 40d813ea0972 to complete readiness checks +[testcontainers.org 00:05:26.97] Docker container 40d813ea0972 ready +[testcontainers.org 00:05:47.61] Docker container 995f11910ea1 created +[testcontainers.org 00:05:47.63] Start Docker container 995f11910ea1 +[testcontainers.org 00:05:48.00] Wait for Docker container 995f11910ea1 to complete readiness checks +[testcontainers.org 00:05:48.01] Docker container 995f11910ea1 ready +[testcontainers.org 00:06:08.50] Docker container 939f1947584d created +[testcontainers.org 00:06:08.51] Start Docker container 939f1947584d +[testcontainers.org 00:06:08.81] Wait for Docker container 939f1947584d to complete readiness checks +[testcontainers.org 00:06:08.81] Docker container 939f1947584d ready +Given I create the following roles + --- table step argument --- + | Role Name | + | Administrator | + | Estate | +-> done: BackgroundSteps.GivenICreateTheFollowingRoles() (0.7s) +Given I create the following api scopes + --- table step argument --- + | Name | DisplayName | Description | + | transactionProcessor | Transaction Processor REST Scope | Scope for Transaction Processor REST | + | fileProcessor | File Processor REST Scope | Scope for File Processor REST | +-> done: BackgroundSteps.GivenICreateTheFollowingApiScopes(
) (0.2s) +Given I create the following api resources + --- table step argument --- + | Name | DisplayName | Secret | Scopes | UserClaims | + | estateManagement | Estate Managememt REST | Secret1 | estateManagement | merchantId,estateId,role | + | transactionProcessor | Transaction Processor REST | Secret1 | transactionProcessor | merchantId,estateId,role | + | fileProcessor | File Processor REST | Secret1 | fileProcessor | merchantId,estateId,role | +-> done: BackgroundSteps.GivenICreateTheFollowingApiResources(
) (0.2s) +Given I create the following identity resources + --- table step argument --- + | Name | DisplayName | Description | UserClaims | + | openid | Your user identifier | | sub | + | profile | User profile | Your user profile information (first name, last name, etc.) | name,role,email,given_name,middle_name,family_name,estateId,merchantId | + | email | Email | Email and Email Verified Flags | email_verified,email | +-> done: BackgroundSteps.GivenICreateTheFollowingIdentityResources(
) (0.2s) +Given I create the following clients + --- table step argument --- + | ClientId | Name | Secret | Scopes | GrantTypes | RedirectUris | PostLogoutRedirectUris | RequireConsent | AllowOfflineAccess | ClientUri | + | serviceClient | Service Client | Secret1 | transactionProcessor | client_credentials | | | | | | + | estateUIClient | Merchant Client | Secret1 | fileProcessor,transactionProcessor,openid,email,profile | hybrid | https://localhost:[port]/signin-oidc | https://localhost:[port]/signout-oidc | false | true | https://[url]:[port] | +-> done: BackgroundSteps.GivenICreateTheFollowingClients(
) (0.2s) +Given I create the following users + --- table step argument --- + | Email Address | Phone Number | Given Name | Middle Name | Family Name | Claims | Roles | + | administrator@admin.co.uk | 123456789 | Test | | User 1 | | Administrator | +-> done: BackgroundSteps.GivenICreateTheFollowingUsers(
) (0.7s) +Given the user navigates to the app address +-> done: DashboardSteps.GivenTheUserNavigatesToTheAppAddress() (1.3s) +And I click on the Sign In Button +Sign in before click: https://localhost:65083/entry +Sign in after click: https://localhost:65083/login +-> done: DashboardSteps.WhenIClickOnTheSignInButton() (2.1s) +Then I am presented with a login screen +-> error: (await IsAnyVisibleAsync( + "#Input_Username", + "input[name='Input.Username']", + "#Username", + "input[name='Username']", + "input[name='username']", + "input[type='email']")) + should be +True + but was +False (0.0s) +When I login with the username 'administrator@admin.co.uk' and password '123456' +-> skipped because of previous errors +Then I should see the dashboard heading +-> skipped because of previous errors +And I should see the administrator welcome panel +-> skipped because of previous errors +And I should not see the merchant KPI summary cards +-> skipped because of previous errors +And I should not see the sales comparison cards +-> skipped because of previous errors +And I should not see the recent merchants section +-> skipped because of previous errors +Screenshot saved to: screenshot-Administrators_see_the_dashboard_welcome_panel-20260619134749.png +[testcontainers.org 00:06:16.87] Stop Docker container 939f1947584d +[testcontainers.org 00:06:17.21] Delete Docker container 939f1947584d +[testcontainers.org 00:06:17.27] Stop Docker container 995f11910ea1 +[testcontainers.org 00:06:17.71] Delete Docker container 995f11910ea1 +[testcontainers.org 00:06:17.74] Stop Docker container 40d813ea0972 +[testcontainers.org 00:06:18.14] Delete Docker container 40d813ea0972 +[testcontainers.org 00:06:18.18] Stop Docker container 7c75f5814a9d +[testcontainers.org 00:06:18.60] Delete Docker container 7c75f5814a9d +[testcontainers.org 00:06:18.64] Stop Docker container 54b1d3f6190d +[testcontainers.org 00:06:20.52] Delete Docker container 54b1d3f6190d +[testcontainers.org 00:06:20.68] Stop Docker container 0ead7ba827ae +[testcontainers.org 00:06:21.30] Delete Docker container 0ead7ba827ae +[testcontainers.org 00:06:21.34] Stop Docker container e7bbcc0242ca +[testcontainers.org 00:06:21.81] Delete Docker container e7bbcc0242ca +[testcontainers.org 00:06:21.86] Stop Docker container 7752202c2996 +[testcontainers.org 00:06:22.33] Delete Docker container 7752202c2996 +[testcontainers.org 00:06:22.41] Stop Docker container 1df1fd9fb44e +[testcontainers.org 00:06:23.65] Delete Docker container 1df1fd9fb44e +[testcontainers.org 00:06:23.89] Stop Docker container 80cc17022ab1 +[testcontainers.org 00:06:25.86] Delete Docker container 80cc17022ab1 +[testcontainers.org 00:06:25.93] Delete Docker network ab5c7ec2ca97 + +TpTrace Verbose: 0 : 53008, 13, 2026/06/19, 13:47:58.794, 6203662611598, testhost.dll, TestRequestHandler.SendData: sending data from testhost: {"Version":7,"MessageType":"TestSession.Message","Payload":{"MessageLevel":0,"Message":"[testcontainers.org 00:00:00.06] Connected to Docker:\r\n Host: npipe://./pipe/docker_engine\r\n Server Version: 29.4.3\r\n Kernel Version: 6.12.76-linuxkit\r\n API Version: 1.54\r\n Operating System: Docker Desktop\r\n Total Memory: 3.82 GB\r\n Labels: \r\n com.docker.desktop.address=npipe://\\\\.\\pipe\\docker_cli\r\n[testcontainers.org 00:00:00.13] Docker network ab5c7ec2ca97 created\r\n[testcontainers.org 00:00:00.40] Docker container bb704f0c4c72 created\r\n[testcontainers.org 00:00:00.46] Start Docker container bb704f0c4c72\r\n[testcontainers.org 00:00:00.72] Wait for Docker container bb704f0c4c72 to complete readiness checks\r\n[testcontainers.org 00:00:01.79] Docker container bb704f0c4c72 ready\r\n[testcontainers.org 00:00:01.90] Docker container 80cc17022ab1 created\r\n[testcontainers.org 00:00:01.91] Start Docker container 80cc17022ab1\r\n[testcontainers.org 00:00:03.92] Wait for Docker container 80cc17022ab1 to complete readiness checks\r\n[testcontainers.org 00:00:03.93] Docker container 80cc17022ab1 ready\r\n[testcontainers.org 00:00:34.37] Docker container 1df1fd9fb44e created\r\n[testcontainers.org 00:00:34.38] Start Docker container 1df1fd9fb44e\r\n[testcontainers.org 00:00:34.58] Wait for Docker container 1df1fd9fb44e to complete readiness checks\r\n[testcontainers.org 00:00:34.59] Docker container 1df1fd9fb44e ready\r\n[testcontainers.org 00:01:34.74] Docker container 7752202c2996 created\r\n[testcontainers.org 00:01:34.75] Start Docker container 7752202c2996\r\n[testcontainers.org 00:01:34.99] Wait for Docker container 7752202c2996 to complete readiness checks\r\n[testcontainers.org 00:01:35.00] Docker container 7752202c2996 ready\r\nAbout to Start Security Container\r\n[testcontainers.org 00:03:55.58] Docker container e7bbcc0242ca created\r\n[testcontainers.org 00:03:55.59] Start Docker container e7bbcc0242ca\r\n[testcontainers.org 00:03:55.87] Wait for Docker container e7bbcc0242ca to complete readiness checks\r\n[testcontainers.org 00:03:55.87] Docker container e7bbcc0242ca ready\r\n[testcontainers.org 00:04:21.97] Docker container 0ead7ba827ae created\r\n[testcontainers.org 00:04:21.98] Start Docker container 0ead7ba827ae\r\n[testcontainers.org 00:04:22.32] Wait for Docker container 0ead7ba827ae to complete readiness checks\r\n[testcontainers.org 00:04:22.33] Docker container 0ead7ba827ae ready\r\n[testcontainers.org 00:04:43.73] Docker container 54b1d3f6190d created\r\n[testcontainers.org 00:04:43.77] Start Docker container 54b1d3f6190d\r\n[testcontainers.org 00:04:44.66] Wait for Docker container 54b1d3f6190d to complete readiness checks\r\n[testcontainers.org 00:04:44.70] Docker container 54b1d3f6190d ready\r\n[testcontainers.org 00:05:05.18] Docker container 7c75f5814a9d created\r\n[testcontainers.org 00:05:05.19] Start Docker container 7c75f5814a9d\r\n[testcontainers.org 00:05:05.45] Wait for Docker container 7c75f5814a9d to complete readiness checks\r\n[testcontainers.org 00:05:05.46] Docker container 7c75f5814a9d ready\r\n[testcontainers.org 00:05:26.34] Docker container 40d813ea0972 created\r\n[testcontainers.org 00:05:26.38] Start Docker container 40d813ea0972\r\n[testcontainers.org 00:05:26.96] Wait for Docker container 40d813ea0972 to complete readiness checks\r\n[testcontainers.org 00:05:26.97] Docker container 40d813ea0972 ready\r\n[testcontainers.org 00:05:47.61] Docker container 995f11910ea1 created\r\n[testcontainers.org 00:05:47.63] Start Docker container 995f11910ea1\r\n[testcontainers.org 00:05:48.00] Wait for Docker container 995f11910ea1 to complete readiness checks\r\n[testcontainers.org 00:05:48.01] Docker container 995f11910ea1 ready\r\n[testcontainers.org 00:06:08.50] Docker container 939f1947584d created\r\n[testcontainers.org 00:06:08.51] Start Docker container 939f1947584d\r\n[testcontainers.org 00:06:08.81] Wait for Docker container 939f1947584d to complete readiness checks\r\n[testcontainers.org 00:06:08.81] Docker container 939f1947584d ready\r\nGiven I create the following roles\r\n --- table step argument ---\r\n | Role Name |\r\n | Administrator |\r\n | Estate |\r\n-> done: BackgroundSteps.GivenICreateTheFollowingRoles(
) (0.7s)\r\nGiven I create the following api scopes\r\n --- table step argument ---\r\n | Name | DisplayName | Description |\r\n | transactionProcessor | Transaction Processor REST Scope | Scope for Transaction Processor REST |\r\n | fileProcessor | File Processor REST Scope | Scope for File Processor REST |\r\n-> done: BackgroundSteps.GivenICreateTheFollowingApiScopes(
) (0.2s)\r\nGiven I create the following api resources\r\n --- table step argument ---\r\n | Name | DisplayName | Secret | Scopes | UserClaims |\r\n | estateManagement | Estate Managememt REST | Secret1 | estateManagement | merchantId,estateId,role |\r\n | transactionProcessor | Transaction Processor REST | Secret1 | transactionProcessor | merchantId,estateId,role |\r\n | fileProcessor | File Processor REST | Secret1 | fileProcessor | merchantId,estateId,role |\r\n-> done: BackgroundSteps.GivenICreateTheFollowingApiResources(
) (0.2s)\r\nGiven I create the following identity resources\r\n --- table step argument ---\r\n | Name | DisplayName | Description | UserClaims |\r\n | openid | Your user identifier | | sub |\r\n | profile | User profile | Your user profile information (first name, last name, etc.) | name,role,email,given_name,middle_name,family_name,estateId,merchantId |\r\n | email | Email | Email and Email Verified Flags | email_verified,email |\r\n-> done: BackgroundSteps.GivenICreateTheFollowingIdentityResources(
) (0.2s)\r\nGiven I create the following clients\r\n --- table step argument ---\r\n | ClientId | Name | Secret | Scopes | GrantTypes | RedirectUris | PostLogoutRedirectUris | RequireConsent | AllowOfflineAccess | ClientUri |\r\n | serviceClient | Service Client | Secret1 | transactionProcessor | client_credentials | | | | | |\r\n | estateUIClient | Merchant Client | Secret1 | fileProcessor,transactionProcessor,openid,email,profile | hybrid | https://localhost:[port]/signin-oidc | https://localhost:[port]/signout-oidc | false | true | https://[url]:[port] |\r\n-> done: BackgroundSteps.GivenICreateTheFollowingClients(
) (0.2s)\r\nGiven I create the following users\r\n --- table step argument ---\r\n | Email Address | Phone Number | Given Name | Middle Name | Family Name | Claims | Roles |\r\n | administrator@admin.co.uk | 123456789 | Test | | User 1 | | Administrator |\r\n-> done: BackgroundSteps.GivenICreateTheFollowingUsers(
) (0.7s)\r\nGiven the user navigates to the app address\r\n-> done: DashboardSteps.GivenTheUserNavigatesToTheAppAddress() (1.3s)\r\nAnd I click on the Sign In Button\r\nSign in before click: https://localhost:65083/entry\r\nSign in after click: https://localhost:65083/login\r\n-> done: DashboardSteps.WhenIClickOnTheSignInButton() (2.1s)\r\nThen I am presented with a login screen\r\n-> error: (await IsAnyVisibleAsync(\r\n \"#Input_Username\",\r\n \"input[name='Input.Username']\",\r\n \"#Username\",\r\n \"input[name='Username']\",\r\n \"input[name='username']\",\r\n \"input[type='email']\"))\r\n should be\r\nTrue\r\n but was\r\nFalse (0.0s)\r\nWhen I login with the username 'administrator@admin.co.uk' and password '123456'\r\n-> skipped because of previous errors\r\nThen I should see the dashboard heading\r\n-> skipped because of previous errors\r\nAnd I should see the administrator welcome panel\r\n-> skipped because of previous errors\r\nAnd I should not see the merchant KPI summary cards\r\n-> skipped because of previous errors\r\nAnd I should not see the sales comparison cards\r\n-> skipped because of previous errors\r\nAnd I should not see the recent merchants section\r\n-> skipped because of previous errors\r\nScreenshot saved to: screenshot-Administrators_see_the_dashboard_welcome_panel-20260619134749.png\r\n[testcontainers.org 00:06:16.87] Stop Docker container 939f1947584d\r\n[testcontainers.org 00:06:17.21] Delete Docker container 939f1947584d\r\n[testcontainers.org 00:06:17.27] Stop Docker container 995f11910ea1\r\n[testcontainers.org 00:06:17.71] Delete Docker container 995f11910ea1\r\n[testcontainers.org 00:06:17.74] Stop Docker container 40d813ea0972\r\n[testcontainers.org 00:06:18.14] Delete Docker container 40d813ea0972\r\n[testcontainers.org 00:06:18.18] Stop Docker container 7c75f5814a9d\r\n[testcontainers.org 00:06:18.60] Delete Docker container 7c75f5814a9d\r\n[testcontainers.org 00:06:18.64] Stop Docker container 54b1d3f6190d\r\n[testcontainers.org 00:06:20.52] Delete Docker container 54b1d3f6190d\r\n[testcontainers.org 00:06:20.68] Stop Docker container 0ead7ba827ae\r\n[testcontainers.org 00:06:21.30] Delete Docker container 0ead7ba827ae\r\n[testcontainers.org 00:06:21.34] Stop Docker container e7bbcc0242ca\r\n[testcontainers.org 00:06:21.81] Delete Docker container e7bbcc0242ca\r\n[testcontainers.org 00:06:21.86] Stop Docker container 7752202c2996\r\n[testcontainers.org 00:06:22.33] Delete Docker container 7752202c2996\r\n[testcontainers.org 00:06:22.41] Stop Docker container 1df1fd9fb44e\r\n[testcontainers.org 00:06:23.65] Delete Docker container 1df1fd9fb44e\r\n[testcontainers.org 00:06:23.89] Stop Docker container 80cc17022ab1\r\n[testcontainers.org 00:06:25.86] Delete Docker container 80cc17022ab1\r\n[testcontainers.org 00:06:25.93] Delete Docker network ab5c7ec2ca97\r\n"}} +TpTrace Verbose: 0 : 53008, 13, 2026/06/19, 13:47:58.795, 6203662615060, testhost.dll, MulticastDelegateUtilities.SafeInvoke: TestRunMessageLoggerProxy.SendMessage: Invoking callback 1/1 for Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.Execution.RunTestsWithSources., took 7 ms. +TpTrace Verbose: 0 : 53008, 13, 2026/06/19, 13:47:58.795, 6203662619542, testhost.dll, TestExecutionRecorder.RecordEnd: test: EstateManagementUI.IntegrationTests.Features.DashboardFeature.AdministratorsSeeTheDashboardWelcomePanel execution completed. +TpTrace Warning: 0 : 53008, 13, 2026/06/19, 13:47:58.796, 6203662625701, testhost.dll, TestRunCache: InProgressTests is null +TpTrace Verbose: 0 : 53008, 13, 2026/06/19, 13:47:58.796, 6203662631861, testhost.dll, TestExecutionRecorder.RecordResult: Received result for test: EstateManagementUI.IntegrationTests.Features.DashboardFeature.AdministratorsSeeTheDashboardWelcomePanel. +TpTrace Warning: 0 : 53008, 13, 2026/06/19, 13:47:58.800, 6203662669988, testhost.dll, TestRunCache: InProgressTests is null +TpTrace Warning: 0 : 53008, 13, 2026/06/19, 13:47:58.801, 6203662673038, testhost.dll, TestRunCache: No test found corresponding to testResult 'AdministratorsSeeTheDashboardWelcomePanel' in inProgress list. +TpTrace Information: 0 : 53008, 28, 2026/06/19, 13:47:59.151, 6203666179110, testhost.dll, Sending test run statistics +TpTrace Verbose: 0 : 53008, 28, 2026/06/19, 13:47:59.164, 6203666304092, testhost.dll, TestRequestHandler.SendData: sending data from testhost: {"Version":7,"MessageType":"TestExecution.StatsChange","Payload":{"NewTestResults":[{"TestCase":{"Id":"856509a0-37bf-5299-e232-e80e305d4dd4","FullyQualifiedName":"EstateManagementUI.IntegrationTests.Features.DashboardFeature.AdministratorsSeeTheDashboardWelcomePanel","DisplayName":"AdministratorsSeeTheDashboardWelcomePanel","ExecutorUri":"executor://NUnit3TestExecutor","Source":"D:\\Projects\\TransactionProcessing\\EstateManagementUI\\EstateManagementUI.IntegrationTests\\bin\\Debug\\net10.0\\EstateManagementUI.IntegrationTests.dll","CodeFilePath":null,"LineNumber":0,"Properties":[{"Key":{"Id":"NUnit.TestCategory","Label":"TestCategory","Category":"","Description":"","Attributes":5,"ValueType":"System.String[]"},"Value":["base","background","dashboard","Dashboard","AdministratorRole"]},{"Key":{"Id":"NUnit.Seed","Label":"Seed","Category":"","Description":"","Attributes":0,"ValueType":"System.String"},"Value":"1743199602"}]},"Attachments":[],"Outcome":2,"ErrorMessage":"Shouldly.ShouldAssertException : (await IsAnyVisibleAsync(\r\n \"#Input_Username\",\r\n \"input[name='Input.Username']\",\r\n \"#Username\",\r\n \"input[name='Username']\",\r\n \"input[name='username']\",\r\n \"input[type='email']\"))\r\n should be\r\nTrue\r\n but was\r\nFalse","ErrorStackTrace":" at EstateManagementUI.IntegrationTests.Common.DashboardPageHelper.AssertLoginScreenVisibleAsync() in D:\\Projects\\TransactionProcessing\\EstateManagementUI\\EstateManagementUI.IntegrationTests\\Common\\DashboardPageHelper.cs:line 42\r\n at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task, ConfigureAwaitOptions options)\r\n at EstateManagementUI.IntegrationTests.Steps.DashboardSteps.ThenIAmPresentedWithALoginScreen() in D:\\Projects\\TransactionProcessing\\EstateManagementUI\\EstateManagementUI.IntegrationTests\\Steps\\DashboardSteps.cs:line 35\r\n at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task, ConfigureAwaitOptions options)\r\n at Reqnroll.Bindings.AsyncMethodHelper.ConvertTaskOfT(Task task, Boolean getValue)\r\n at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task, ConfigureAwaitOptions options)\r\n at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()\r\n at Reqnroll.Bindings.BindingDelegateInvoker.InvokeDelegateAsync(Delegate bindingDelegate, Object[] invokeArgs, ExecutionContextHolder executionContext)\r\n at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task, ConfigureAwaitOptions options)\r\n at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()\r\n at Reqnroll.Bindings.BindingInvoker.InvokeBindingAsync(IBinding binding, IContextManager contextManager, Object[] arguments, ITestTracer testTracer, DurationHolder durationHolder)\r\n at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task, ConfigureAwaitOptions options)\r\n at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()\r\n at Reqnroll.Infrastructure.TestExecutionEngine.ExecuteStepMatchAsync(BindingMatch match, Object[] arguments, DurationHolder durationHolder)\r\n at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n at Reqnroll.Infrastructure.TestExecutionEngine.ExecuteStepMatchAsync(BindingMatch match, Object[] arguments, DurationHolder durationHolder)\r\n at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task, ConfigureAwaitOptions options)\r\n at Reqnroll.Infrastructure.TestExecutionEngine.<>c__DisplayClass57_0.<b__7>d.MoveNext()\r\n--- End of stack trace from previous location ---\r\n at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task, ConfigureAwaitOptions options)\r\n at Reqnroll.Infrastructure.TestExecutionEngine.<>c__DisplayClass57_0.<g__HandleStepExecutionExceptions|0>d.MoveNext()\n1) at EstateManagementUI.IntegrationTests.Common.DashboardPageHelper.AssertLoginScreenVisibleAsync() in D:\\Projects\\TransactionProcessing\\EstateManagementUI\\EstateManagementUI.IntegrationTests\\Common\\DashboardPageHelper.cs:line 42\r\n at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task, ConfigureAwaitOptions options)\r\n at EstateManagementUI.IntegrationTests.Steps.DashboardSteps.ThenIAmPresentedWithALoginScreen() in D:\\Projects\\TransactionProcessing\\EstateManagementUI\\EstateManagementUI.IntegrationTests\\Steps\\DashboardSteps.cs:line 35\r\n at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task, ConfigureAwaitOptions options)\r\n at Reqnroll.Bindings.AsyncMethodHelper.ConvertTaskOfT(Task task, Boolean getValue)\r\n at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task, ConfigureAwaitOptions options)\r\n at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()\r\n at Reqnroll.Bindings.BindingDelegateInvoker.InvokeDelegateAsync(Delegate bindingDelegate, Object[] invokeArgs, ExecutionContextHolder executionContext)\r\n at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task, ConfigureAwaitOptions options)\r\n at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()\r\n at Reqnroll.Bindings.BindingInvoker.InvokeBindingAsync(IBinding binding, IContextManager contextManager, Object[] arguments, ITestTracer testTracer, DurationHolder durationHolder)\r\n at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task, ConfigureAwaitOptions options)\r\n at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()\r\n at Reqnroll.Infrastructure.TestExecutionEngine.ExecuteStepMatchAsync(BindingMatch match, Object[] arguments, DurationHolder durationHolder)\r\n at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n at Reqnroll.Infrastructure.TestExecutionEngine.ExecuteStepMatchAsync(BindingMatch match, Object[] arguments, DurationHolder durationHolder)\r\n at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task, ConfigureAwaitOptions options)\r\n at Reqnroll.Infrastructure.TestExecutionEngine.<>c__DisplayClass57_0.<b__7>d.MoveNext()\r\n--- End of stack trace from previous location ---\r\n at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task, ConfigureAwaitOptions options)\r\n at Reqnroll.Infrastructure.TestExecutionEngine.<>c__DisplayClass57_0.<g__HandleStepExecutionExceptions|0>d.MoveNext()\n","DisplayName":"AdministratorsSeeTheDashboardWelcomePanel","Messages":[{"Category":"StdOutMsgs","Text":"[testcontainers.org 00:00:00.06] Connected to Docker:\r\n Host: npipe://./pipe/docker_engine\r\n Server Version: 29.4.3\r\n Kernel Version: 6.12.76-linuxkit\r\n API Version: 1.54\r\n Operating System: Docker Desktop\r\n Total Memory: 3.82 GB\r\n Labels: \r\n com.docker.desktop.address=npipe://\\\\.\\pipe\\docker_cli\r\n[testcontainers.org 00:00:00.13] Docker network ab5c7ec2ca97 created\r\n[testcontainers.org 00:00:00.40] Docker container bb704f0c4c72 created\r\n[testcontainers.org 00:00:00.46] Start Docker container bb704f0c4c72\r\n[testcontainers.org 00:00:00.72] Wait for Docker container bb704f0c4c72 to complete readiness checks\r\n[testcontainers.org 00:00:01.79] Docker container bb704f0c4c72 ready\r\n[testcontainers.org 00:00:01.90] Docker container 80cc17022ab1 created\r\n[testcontainers.org 00:00:01.91] Start Docker container 80cc17022ab1\r\n[testcontainers.org 00:00:03.92] Wait for Docker container 80cc17022ab1 to complete readiness checks\r\n[testcontainers.org 00:00:03.93] Docker container 80cc17022ab1 ready\r\n[testcontainers.org 00:00:34.37] Docker container 1df1fd9fb44e created\r\n[testcontainers.org 00:00:34.38] Start Docker container 1df1fd9fb44e\r\n[testcontainers.org 00:00:34.58] Wait for Docker container 1df1fd9fb44e to complete readiness checks\r\n[testcontainers.org 00:00:34.59] Docker container 1df1fd9fb44e ready\r\n[testcontainers.org 00:01:34.74] Docker container 7752202c2996 created\r\n[testcontainers.org 00:01:34.75] Start Docker container 7752202c2996\r\n[testcontainers.org 00:01:34.99] Wait for Docker container 7752202c2996 to complete readiness checks\r\n[testcontainers.org 00:01:35.00] Docker container 7752202c2996 ready\r\nAbout to Start Security Container\r\n[testcontainers.org 00:03:55.58] Docker container e7bbcc0242ca created\r\n[testcontainers.org 00:03:55.59] Start Docker container e7bbcc0242ca\r\n[testcontainers.org 00:03:55.87] Wait for Docker container e7bbcc0242ca to complete readiness checks\r\n[testcontainers.org 00:03:55.87] Docker container e7bbcc0242ca ready\r\n[testcontainers.org 00:04:21.97] Docker container 0ead7ba827ae created\r\n[testcontainers.org 00:04:21.98] Start Docker container 0ead7ba827ae\r\n[testcontainers.org 00:04:22.32] Wait for Docker container 0ead7ba827ae to complete readiness checks\r\n[testcontainers.org 00:04:22.33] Docker container 0ead7ba827ae ready\r\n[testcontainers.org 00:04:43.73] Docker container 54b1d3f6190d created\r\n[testcontainers.org 00:04:43.77] Start Docker container 54b1d3f6190d\r\n[testcontainers.org 00:04:44.66] Wait for Docker container 54b1d3f6190d to complete readiness checks\r\n[testcontainers.org 00:04:44.70] Docker container 54b1d3f6190d ready\r\n[testcontainers.org 00:05:05.18] Docker container 7c75f5814a9d created\r\n[testcontainers.org 00:05:05.19] Start Docker container 7c75f5814a9d\r\n[testcontainers.org 00:05:05.45] Wait for Docker container 7c75f5814a9d to complete readiness checks\r\n[testcontainers.org 00:05:05.46] Docker container 7c75f5814a9d ready\r\n[testcontainers.org 00:05:26.34] Docker container 40d813ea0972 created\r\n[testcontainers.org 00:05:26.38] Start Docker container 40d813ea0972\r\n[testcontainers.org 00:05:26.96] Wait for Docker container 40d813ea0972 to complete readiness checks\r\n[testcontainers.org 00:05:26.97] Docker container 40d813ea0972 ready\r\n[testcontainers.org 00:05:47.61] Docker container 995f11910ea1 created\r\n[testcontainers.org 00:05:47.63] Start Docker container 995f11910ea1\r\n[testcontainers.org 00:05:48.00] Wait for Docker container 995f11910ea1 to complete readiness checks\r\n[testcontainers.org 00:05:48.01] Docker container 995f11910ea1 ready\r\n[testcontainers.org 00:06:08.50] Docker container 939f1947584d created\r\n[testcontainers.org 00:06:08.51] Start Docker container 939f1947584d\r\n[testcontainers.org 00:06:08.81] Wait for Docker container 939f1947584d to complete readiness checks\r\n[testcontainers.org 00:06:08.81] Docker container 939f1947584d ready\r\nGiven I create the following roles\r\n --- table step argument ---\r\n | Role Name |\r\n | Administrator |\r\n | Estate |\r\n-> done: BackgroundSteps.GivenICreateTheFollowingRoles(
) (0.7s)\r\nGiven I create the following api scopes\r\n --- table step argument ---\r\n | Name | DisplayName | Description |\r\n | transactionProcessor | Transaction Processor REST Scope | Scope for Transaction Processor REST |\r\n | fileProcessor | File Processor REST Scope | Scope for File Processor REST |\r\n-> done: BackgroundSteps.GivenICreateTheFollowingApiScopes(
) (0.2s)\r\nGiven I create the following api resources\r\n --- table step argument ---\r\n | Name | DisplayName | Secret | Scopes | UserClaims |\r\n | estateManagement | Estate Managememt REST | Secret1 | estateManagement | merchantId,estateId,role |\r\n | transactionProcessor | Transaction Processor REST | Secret1 | transactionProcessor | merchantId,estateId,role |\r\n | fileProcessor | File Processor REST | Secret1 | fileProcessor | merchantId,estateId,role |\r\n-> done: BackgroundSteps.GivenICreateTheFollowingApiResources(
) (0.2s)\r\nGiven I create the following identity resources\r\n --- table step argument ---\r\n | Name | DisplayName | Description | UserClaims |\r\n | openid | Your user identifier | | sub |\r\n | profile | User profile | Your user profile information (first name, last name, etc.) | name,role,email,given_name,middle_name,family_name,estateId,merchantId |\r\n | email | Email | Email and Email Verified Flags | email_verified,email |\r\n-> done: BackgroundSteps.GivenICreateTheFollowingIdentityResources(
) (0.2s)\r\nGiven I create the following clients\r\n --- table step argument ---\r\n | ClientId | Name | Secret | Scopes | GrantTypes | RedirectUris | PostLogoutRedirectUris | RequireConsent | AllowOfflineAccess | ClientUri |\r\n | serviceClient | Service Client | Secret1 | transactionProcessor | client_credentials | | | | | |\r\n | estateUIClient | Merchant Client | Secret1 | fileProcessor,transactionProcessor,openid,email,profile | hybrid | https://localhost:[port]/signin-oidc | https://localhost:[port]/signout-oidc | false | true | https://[url]:[port] |\r\n-> done: BackgroundSteps.GivenICreateTheFollowingClients(
) (0.2s)\r\nGiven I create the following users\r\n --- table step argument ---\r\n | Email Address | Phone Number | Given Name | Middle Name | Family Name | Claims | Roles |\r\n | administrator@admin.co.uk | 123456789 | Test | | User 1 | | Administrator |\r\n-> done: BackgroundSteps.GivenICreateTheFollowingUsers(
) (0.7s)\r\nGiven the user navigates to the app address\r\n-> done: DashboardSteps.GivenTheUserNavigatesToTheAppAddress() (1.3s)\r\nAnd I click on the Sign In Button\r\nSign in before click: https://localhost:65083/entry\r\nSign in after click: https://localhost:65083/login\r\n-> done: DashboardSteps.WhenIClickOnTheSignInButton() (2.1s)\r\nThen I am presented with a login screen\r\n-> error: (await IsAnyVisibleAsync(\r\n \"#Input_Username\",\r\n \"input[name='Input.Username']\",\r\n \"#Username\",\r\n \"input[name='Username']\",\r\n \"input[name='username']\",\r\n \"input[type='email']\"))\r\n should be\r\nTrue\r\n but was\r\nFalse (0.0s)\r\nWhen I login with the username 'administrator@admin.co.uk' and password '123456'\r\n-> skipped because of previous errors\r\nThen I should see the dashboard heading\r\n-> skipped because of previous errors\r\nAnd I should see the administrator welcome panel\r\n-> skipped because of previous errors\r\nAnd I should not see the merchant KPI summary cards\r\n-> skipped because of previous errors\r\nAnd I should not see the sales comparison cards\r\n-> skipped because of previous errors\r\nAnd I should not see the recent merchants section\r\n-> skipped because of previous errors\r\nScreenshot saved to: screenshot-Administrators_see_the_dashboard_welcome_panel-20260619134749.png\r\n[testcontainers.org 00:06:16.87] Stop Docker container 939f1947584d\r\n[testcontainers.org 00:06:17.21] Delete Docker container 939f1947584d\r\n[testcontainers.org 00:06:17.27] Stop Docker container 995f11910ea1\r\n[testcontainers.org 00:06:17.71] Delete Docker container 995f11910ea1\r\n[testcontainers.org 00:06:17.74] Stop Docker container 40d813ea0972\r\n[testcontainers.org 00:06:18.14] Delete Docker container 40d813ea0972\r\n[testcontainers.org 00:06:18.18] Stop Docker container 7c75f5814a9d\r\n[testcontainers.org 00:06:18.60] Delete Docker container 7c75f5814a9d\r\n[testcontainers.org 00:06:18.64] Stop Docker container 54b1d3f6190d\r\n[testcontainers.org 00:06:20.52] Delete Docker container 54b1d3f6190d\r\n[testcontainers.org 00:06:20.68] Stop Docker container 0ead7ba827ae\r\n[testcontainers.org 00:06:21.30] Delete Docker container 0ead7ba827ae\r\n[testcontainers.org 00:06:21.34] Stop Docker container e7bbcc0242ca\r\n[testcontainers.org 00:06:21.81] Delete Docker container e7bbcc0242ca\r\n[testcontainers.org 00:06:21.86] Stop Docker container 7752202c2996\r\n[testcontainers.org 00:06:22.33] Delete Docker container 7752202c2996\r\n[testcontainers.org 00:06:22.41] Stop Docker container 1df1fd9fb44e\r\n[testcontainers.org 00:06:23.65] Delete Docker container 1df1fd9fb44e\r\n[testcontainers.org 00:06:23.89] Stop Docker container 80cc17022ab1\r\n[testcontainers.org 00:06:25.86] Delete Docker container 80cc17022ab1\r\n[testcontainers.org 00:06:25.93] Delete Docker network ab5c7ec2ca97\r\n"}],"ComputerName":"DESKTOP-FJ3HD6D","Duration":"00:06:26.6414899","StartTime":"2026-06-19T12:41:32.1201917+00:00","EndTime":"2026-06-19T12:47:58.7615187+00:00","Properties":[{"Key":{"Id":"NUnit.Seed","Label":"Seed","Category":"","Description":"","Attributes":0,"ValueType":"System.String"},"Value":"1743199602"}]}],"TestRunStatistics":{"ExecutedTests":1,"Stats":{"Failed":1}},"ActiveTests":[]}} +TpTrace Verbose: 0 : 53008, 28, 2026/06/19, 13:47:59.166, 6203666325724, testhost.dll, TestRunCache: OnNewTestResult: Notified the onCacheHit callback. +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:47:59.547, 6203670140333, testhost.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 after 1009 ms +TpTrace Verbose: 0 : 53008, 4, 2026/06/19, 13:48:00.313, 6203677798612, testhost.dll, BaseRunTests.RunTestInternalWithExecutors: Completed running tests for executor://NUnit3TestExecutor +TpTrace Information: 0 : 53008, 4, 2026/06/19, 13:48:00.318, 6203677849273, testhost.dll, Sending test run complete +TpTrace Verbose: 0 : 53008, 4, 2026/06/19, 13:48:00.335, 6203678019424, testhost.dll, TestRequestHandler.SendData: sending data from testhost: {"Version":7,"MessageType":"TestExecution.Completed","Payload":{"TestRunCompleteArgs":{"TestRunStatistics":{"ExecutedTests":1,"Stats":{"Failed":1}},"IsCanceled":false,"IsAborted":false,"Error":null,"AttachmentSets":[],"InvokedDataCollectors":[],"ElapsedTimeInRunningTests":"00:06:29.7681925","Metrics":{},"DiscoveredExtensions":{"TestDiscoverers":["NUnit.VisualStudio.TestAdapter.NUnit3TestDiscoverer, NUnit3.TestAdapter, Version=1.0.0.0, Culture=neutral, PublicKeyToken=4cb40d35494691ac"],"TestExecutors":["executor://NUnit3TestExecutor"],"TestExecutors2":[],"TestSettingsProviders":[]}},"LastRunTests":{"NewTestResults":[],"TestRunStatistics":{"ExecutedTests":1,"Stats":{"Failed":1}},"ActiveTests":[]},"RunAttachments":[],"ExecutorUris":["executor://nunit3testexecutor/"]}} +TpTrace Verbose: 0 : 53008, 4, 2026/06/19, 13:48:00.336, 6203678024106, testhost.dll, BaseRunTests.RunTests: Run is complete. +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:48:00.336, 6203678029089, testhost.dll, TcpClientExtensions.MessageLoopAsync: NotifyDataAvailable remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 +TpTrace Information: 0 : 53008, 9, 2026/06/19, 13:48:00.336, 6203678030223, testhost.dll, TestRequestHandler.OnMessageReceived: received message: (TestSession.Terminate) -> {"MessageType":"TestSession.Terminate","Payload":null} +TpTrace Information: 0 : 53008, 9, 2026/06/19, 13:48:00.336, 6203678031020, testhost.dll, Session End message received from server. Closing the connection. +TpTrace Information: 0 : 53008, 9, 2026/06/19, 13:48:00.337, 6203678037237, testhost.dll, SocketClient.Stop: Stop communication from server endpoint: 127.0.0.1:062255 +TpTrace Information: 0 : 53008, 2, 2026/06/19, 13:48:00.337, 6203678037269, testhost.dll, SocketClient.Stop: Stop communication from server endpoint: 127.0.0.1:062255 +TpTrace Information: 0 : 53008, 9, 2026/06/19, 13:48:00.337, 6203678037736, testhost.dll, SocketClient: Stop: Cancellation requested. Stopping message loop. +TpTrace Information: 0 : 53008, 2, 2026/06/19, 13:48:00.337, 6203678038258, testhost.dll, SocketClient: Stop: Cancellation requested. Stopping message loop. +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:48:00.337, 6203678040121, testhost.dll, LengthPrefixCommunicationChannel.Dispose: Dispose reader and writer. +TpTrace Verbose: 0 : 53008, 2, 2026/06/19, 13:48:00.337, 6203678040179, testhost.dll, LengthPrefixCommunicationChannel.Dispose: Dispose reader and writer. +TpTrace Information: 0 : 53008, 9, 2026/06/19, 13:48:00.337, 6203678040824, testhost.dll, Closing the connection ! +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:48:00.337, 6203678041864, testhost.dll, MulticastDelegateUtilities.SafeInvoke: LengthPrefixCommunicationChannel: MessageReceived: Invoking callback 1/1 for Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.TestRequestHandler., took 1 ms. +TpTrace Information: 0 : 53008, 2, 2026/06/19, 13:48:00.338, 6203678042584, testhost.dll, Testhost process exiting. +TpTrace Information: 0 : 53008, 9, 2026/06/19, 13:48:00.338, 6203678044990, testhost.dll, SocketClient.PrivateStop: Stop communication from server endpoint: 127.0.0.1:062255, error: +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:48:00.338, 6203678047166, testhost.dll, LengthPrefixCommunicationChannel.Dispose: Dispose reader and writer. +TpTrace Verbose: 0 : 53008, 9, 2026/06/19, 13:48:00.338, 6203678047795, testhost.dll, TcpClientExtensions.MessageLoopAsync: exiting MessageLoopAsync remoteEndPoint: [::ffff:127.0.0.1]:62255 localEndPoint: [::ffff:127.0.0.1]:62256 diff --git a/EstateManagementUI.IntegrationTests/testdiag.txt b/EstateManagementUI.IntegrationTests/testdiag.txt new file mode 100644 index 00000000..a9b8cdf0 --- /dev/null +++ b/EstateManagementUI.IntegrationTests/testdiag.txt @@ -0,0 +1,755 @@ +TpTrace Verbose: 0 : 48056, 2, 2026/06/19, 13:41:29.896, 6199773631233, vstest.console.dll, Version: 18.6.0-release-26270-133 Current process architecture: X64 +TpTrace Verbose: 0 : 48056, 2, 2026/06/19, 13:41:29.899, 6199773652790, vstest.console.dll, Runtime location: C:\Program Files\dotnet\shared\Microsoft.NETCore.App\10.0.9 +TpTrace Information: 0 : 48056, 2, 2026/06/19, 13:41:29.901, 6199773681474, vstest.console.dll, Using .Net Framework version:.NETCoreApp,Version=v10.0 +TpTrace Verbose: 0 : 48056, 2, 2026/06/19, 13:41:29.902, 6199773682411, vstest.console.dll, ArtifactProcessingPostProcessModeProcessorExecutor.Initialize: ArtifactProcessingMode.Collect +TpTrace Verbose: 0 : 48056, 2, 2026/06/19, 13:41:29.902, 6199773683114, vstest.console.dll, TestSessionCorrelationIdProcessorModeProcessorExecutor.Initialize: TestSessionCorrelationId '64584_2e1b4541-b607-45d6-bf64-ae1a68d4a33e' +TpTrace Information: 0 : 48056, 2, 2026/06/19, 13:41:29.908, 6199773748643, vstest.console.dll, FilePatternParser: The given file D:\Projects\TransactionProcessing\EstateManagementUI\EstateManagementUI.IntegrationTests\bin\Debug\net10.0\EstateManagementUI.IntegrationTests.dll is a full path. +TpTrace Verbose: 0 : 48056, 2, 2026/06/19, 13:41:29.913, 6199773797675, vstest.console.dll, TestPluginCache.DiscoverTestExtensions: finding test extensions in assemblies ends with: RuntimeProvider.dll TPluginInfo: Microsoft.VisualStudio.TestPlatform.Common.ExtensionFramework.Utilities.TestRuntimePluginInformation TExtension: Microsoft.VisualStudio.TestPlatform.ObjectModel.Host.ITestRuntimeProvider +TpTrace Verbose: 0 : 48056, 2, 2026/06/19, 13:41:29.914, 6199773805432, vstest.console.dll, TestPluginCache.GetExtensionPaths: Filtered extension paths: +TpTrace Verbose: 0 : 48056, 2, 2026/06/19, 13:41:29.914, 6199773806482, vstest.console.dll, TestPluginCache.GetExtensionPaths: Added default extension paths: C:\Program Files\dotnet\sdk\10.0.301\Extensions\Microsoft.Diagnostics.NETCore.Client.dll +C:\Program Files\dotnet\sdk\10.0.301\Extensions\Microsoft.TestPlatform.Extensions.BlameDataCollector.dll +C:\Program Files\dotnet\sdk\10.0.301\Extensions\Microsoft.TestPlatform.Extensions.EventLogCollector.dll +C:\Program Files\dotnet\sdk\10.0.301\Extensions\Microsoft.TestPlatform.TestHostRuntimeProvider.dll +C:\Program Files\dotnet\sdk\10.0.301\Extensions\Microsoft.VisualStudio.TestPlatform.Extensions.Html.TestLogger.dll +C:\Program Files\dotnet\sdk\10.0.301\Extensions\Microsoft.VisualStudio.TestPlatform.Extensions.Trx.TestLogger.dll +TpTrace Verbose: 0 : 48056, 2, 2026/06/19, 13:41:29.914, 6199773806914, vstest.console.dll, TestPluginCache.GetExtensionPaths: Added unfilterableExtensionPaths: +TpTrace Information: 0 : 48056, 2, 2026/06/19, 13:41:29.915, 6199773813345, vstest.console.dll, AssemblyResolver.ctor: Creating AssemblyResolver with searchDirectories C:\Program Files\dotnet\sdk\10.0.301\Extensions,C:\Program Files\dotnet\sdk\10.0.301 +TpTrace Verbose: 0 : 48056, 2, 2026/06/19, 13:41:29.915, 6199773821038, vstest.console.dll, TestPluginCache.DiscoverTestExtensions: Discovering the extensions using extension path. +TpTrace Verbose: 0 : 48056, 2, 2026/06/19, 13:41:29.916, 6199773822092, vstest.console.dll, TestPluginCache.GetExtensionPaths: Filtered extension paths: +TpTrace Verbose: 0 : 48056, 2, 2026/06/19, 13:41:29.916, 6199773822472, vstest.console.dll, TestPluginCache.GetExtensionPaths: Added default extension paths: C:\Program Files\dotnet\sdk\10.0.301\Extensions\Microsoft.Diagnostics.NETCore.Client.dll +C:\Program Files\dotnet\sdk\10.0.301\Extensions\Microsoft.TestPlatform.Extensions.BlameDataCollector.dll +C:\Program Files\dotnet\sdk\10.0.301\Extensions\Microsoft.TestPlatform.Extensions.EventLogCollector.dll +C:\Program Files\dotnet\sdk\10.0.301\Extensions\Microsoft.TestPlatform.TestHostRuntimeProvider.dll +C:\Program Files\dotnet\sdk\10.0.301\Extensions\Microsoft.VisualStudio.TestPlatform.Extensions.Html.TestLogger.dll +C:\Program Files\dotnet\sdk\10.0.301\Extensions\Microsoft.VisualStudio.TestPlatform.Extensions.Trx.TestLogger.dll +TpTrace Verbose: 0 : 48056, 2, 2026/06/19, 13:41:29.916, 6199773822706, vstest.console.dll, TestPluginCache.GetExtensionPaths: Added unfilterableExtensionPaths: +TpTrace Verbose: 0 : 48056, 2, 2026/06/19, 13:41:29.916, 6199773823184, vstest.console.dll, TestPluginCache.DiscoverTestExtensions: Discovering the extensions using allExtensionPaths: C:\Program Files\dotnet\sdk\10.0.301\Extensions\Microsoft.Diagnostics.NETCore.Client.dll +C:\Program Files\dotnet\sdk\10.0.301\Extensions\Microsoft.TestPlatform.Extensions.BlameDataCollector.dll +C:\Program Files\dotnet\sdk\10.0.301\Extensions\Microsoft.TestPlatform.Extensions.EventLogCollector.dll +C:\Program Files\dotnet\sdk\10.0.301\Extensions\Microsoft.TestPlatform.TestHostRuntimeProvider.dll +C:\Program Files\dotnet\sdk\10.0.301\Extensions\Microsoft.VisualStudio.TestPlatform.Extensions.Html.TestLogger.dll +C:\Program Files\dotnet\sdk\10.0.301\Extensions\Microsoft.VisualStudio.TestPlatform.Extensions.Trx.TestLogger.dll +TpTrace Information: 0 : 48056, 2, 2026/06/19, 13:41:29.916, 6199773824257, vstest.console.dll, AssemblyResolver.AddSearchDirectories: Adding more searchDirectories C:\Program Files\dotnet\sdk\10.0.301\Extensions,C:\Program Files\dotnet\sdk\10.0.301 +TpTrace Information: 0 : 48056, 2, 2026/06/19, 13:41:29.916, 6199773824770, vstest.console.dll, AssemblyResolver.AddSearchDirectories: Adding more searchDirectories C:\Program Files\dotnet\sdk\10.0.301\Extensions,C:\Program Files\dotnet\sdk\10.0.301 +TpTrace Information: 0 : 48056, 2, 2026/06/19, 13:41:29.916, 6199773825108, vstest.console.dll, AssemblyResolver.AddSearchDirectories: Adding more searchDirectories C:\Program Files\dotnet\sdk\10.0.301\Extensions,C:\Program Files\dotnet\sdk\10.0.301 +TpTrace Information: 0 : 48056, 2, 2026/06/19, 13:41:29.916, 6199773825370, vstest.console.dll, AssemblyResolver.AddSearchDirectories: Adding more searchDirectories C:\Program Files\dotnet\sdk\10.0.301\Extensions,C:\Program Files\dotnet\sdk\10.0.301 +TpTrace Information: 0 : 48056, 2, 2026/06/19, 13:41:29.916, 6199773825607, vstest.console.dll, AssemblyResolver.AddSearchDirectories: Adding more searchDirectories C:\Program Files\dotnet\sdk\10.0.301\Extensions,C:\Program Files\dotnet\sdk\10.0.301 +TpTrace Information: 0 : 48056, 2, 2026/06/19, 13:41:29.916, 6199773825872, vstest.console.dll, AssemblyResolver.AddSearchDirectories: Adding more searchDirectories C:\Program Files\dotnet\sdk\10.0.301\Extensions,C:\Program Files\dotnet\sdk\10.0.301 +TpTrace Information: 0 : 48056, 2, 2026/06/19, 13:41:29.916, 6199773828653, vstest.console.dll, AssemblyResolver.OnResolve: Microsoft.Diagnostics.NETCore.Client: Resolving assembly. +TpTrace Information: 0 : 48056, 2, 2026/06/19, 13:41:29.916, 6199773829337, vstest.console.dll, AssemblyResolver.OnResolve: Microsoft.Diagnostics.NETCore.Client: Searching in: 'C:\Program Files\dotnet\sdk\10.0.301\Extensions'. +TpTrace Information: 0 : 48056, 2, 2026/06/19, 13:41:29.928, 6199773943141, vstest.console.dll, AssemblyResolver.OnResolve: Microsoft.Diagnostics.NETCore.Client: Loading assembly 'C:\Program Files\dotnet\sdk\10.0.301\Extensions\Microsoft.Diagnostics.NETCore.Client.dll'. +TpTrace Information: 0 : 48056, 2, 2026/06/19, 13:41:29.930, 6199773965661, vstest.console.dll, AssemblyResolver.TrackProvidedDependency: Resolved 'Microsoft.Diagnostics.NETCore.Client' from 'C:\Program Files\dotnet\sdk\10.0.301\Extensions' for 'unknown'. +TpTrace Information: 0 : 48056, 2, 2026/06/19, 13:41:29.930, 6199773966778, vstest.console.dll, AssemblyResolver.OnResolve: Resolved assembly: Microsoft.Diagnostics.NETCore.Client, from path: C:\Program Files\dotnet\sdk\10.0.301\Extensions\Microsoft.Diagnostics.NETCore.Client.dll +TpTrace Verbose: 0 : 48056, 2, 2026/06/19, 13:41:29.932, 6199773983115, vstest.console.dll, MetadataReaderExtensionsHelper: Discovering extensions inside assembly 'Microsoft.Diagnostics.NETCore.Client, Version=0.2.14.27133, Culture=neutral, PublicKeyToken=31bf3856ad364e35' file path 'C:\Program Files\dotnet\sdk\10.0.301\Extensions\Microsoft.Diagnostics.NETCore.Client.dll' +TpTrace Information: 0 : 48056, 2, 2026/06/19, 13:41:29.933, 6199774001805, vstest.console.dll, AssemblyResolver.OnResolve: Microsoft.Bcl.AsyncInterfaces: Resolving assembly. +TpTrace Information: 0 : 48056, 2, 2026/06/19, 13:41:29.934, 6199774002424, vstest.console.dll, AssemblyResolver.OnResolve: Microsoft.Bcl.AsyncInterfaces: Searching in: 'C:\Program Files\dotnet\sdk\10.0.301\Extensions'. +TpTrace Information: 0 : 48056, 2, 2026/06/19, 13:41:29.934, 6199774003171, vstest.console.dll, AssemblyResolver.OnResolve: Microsoft.Bcl.AsyncInterfaces: Assembly path does not exist: 'C:\Program Files\dotnet\sdk\10.0.301\Extensions\Microsoft.Bcl.AsyncInterfaces.dll', returning. +TpTrace Information: 0 : 48056, 2, 2026/06/19, 13:41:29.934, 6199774003699, vstest.console.dll, AssemblyResolver.OnResolve: Microsoft.Bcl.AsyncInterfaces: Assembly path does not exist: 'C:\Program Files\dotnet\sdk\10.0.301\Extensions\Microsoft.Bcl.AsyncInterfaces.exe', returning. +TpTrace Information: 0 : 48056, 2, 2026/06/19, 13:41:29.934, 6199774003980, vstest.console.dll, AssemblyResolver.OnResolve: Microsoft.Bcl.AsyncInterfaces: Searching in: 'C:\Program Files\dotnet\sdk\10.0.301'. +TpTrace Information: 0 : 48056, 2, 2026/06/19, 13:41:29.934, 6199774004578, vstest.console.dll, AssemblyResolver.OnResolve: Microsoft.Bcl.AsyncInterfaces: Assembly path does not exist: 'C:\Program Files\dotnet\sdk\10.0.301\Microsoft.Bcl.AsyncInterfaces.dll', returning. +TpTrace Information: 0 : 48056, 2, 2026/06/19, 13:41:29.934, 6199774005373, vstest.console.dll, AssemblyResolver.OnResolve: Microsoft.Bcl.AsyncInterfaces: Assembly path does not exist: 'C:\Program Files\dotnet\sdk\10.0.301\Microsoft.Bcl.AsyncInterfaces.exe', returning. +TpTrace Information: 0 : 48056, 2, 2026/06/19, 13:41:29.934, 6199774005655, vstest.console.dll, AssemblyResolver.OnResolve: Microsoft.Bcl.AsyncInterfaces: Failed to load assembly. +TpTrace Verbose: 0 : 48056, 2, 2026/06/19, 13:41:29.934, 6199774005949, vstest.console.dll, CurrentDomainAssemblyResolve: Resolving assembly 'Microsoft.Bcl.AsyncInterfaces'. +TpTrace Information: 0 : 48056, 2, 2026/06/19, 13:41:29.934, 6199774006549, vstest.console.dll, AssemblyResolver.OnResolve: Microsoft.Bcl.AsyncInterfaces: Resolving assembly. +TpTrace Information: 0 : 48056, 2, 2026/06/19, 13:41:29.934, 6199774006855, vstest.console.dll, AssemblyResolver.OnResolve: Microsoft.Bcl.AsyncInterfaces: Resolved from cache. +TpTrace Verbose: 0 : 48056, 2, 2026/06/19, 13:41:29.934, 6199774008315, vstest.console.dll, CurrentDomainAssemblyResolve: Resolving assembly 'Microsoft.Bcl.AsyncInterfaces'. +TpTrace Verbose: 0 : 48056, 2, 2026/06/19, 13:41:29.934, 6199774008650, vstest.console.dll, CurrentDomainAssemblyResolve: Failed to resolve assembly 'Microsoft.Bcl.AsyncInterfaces'. +TpTrace Verbose: 0 : 48056, 2, 2026/06/19, 13:41:29.935, 6199774014700, vstest.console.dll, CurrentDomainAssemblyResolve: Failed to resolve assembly 'Microsoft.Bcl.AsyncInterfaces'. +TpTrace Information: 0 : 48056, 2, 2026/06/19, 13:41:29.937, 6199774039269, vstest.console.dll, AssemblyResolver.OnResolve: Microsoft.Bcl.AsyncInterfaces: Resolving assembly. +TpTrace Information: 0 : 48056, 2, 2026/06/19, 13:41:29.937, 6199774039869, vstest.console.dll, AssemblyResolver.OnResolve: Microsoft.Bcl.AsyncInterfaces: Resolved from cache. +TpTrace Verbose: 0 : 48056, 2, 2026/06/19, 13:41:29.937, 6199774040148, vstest.console.dll, CurrentDomainAssemblyResolve: Resolving assembly 'Microsoft.Bcl.AsyncInterfaces'. +TpTrace Verbose: 0 : 48056, 2, 2026/06/19, 13:41:29.937, 6199774040379, vstest.console.dll, CurrentDomainAssemblyResolve: Failed to resolve assembly 'Microsoft.Bcl.AsyncInterfaces'. +TpTrace Information: 0 : 48056, 2, 2026/06/19, 13:41:29.938, 6199774050659, vstest.console.dll, AssemblyResolver.OnResolve: Microsoft.Bcl.AsyncInterfaces: Resolving assembly. +TpTrace Information: 0 : 48056, 2, 2026/06/19, 13:41:29.938, 6199774051063, vstest.console.dll, AssemblyResolver.OnResolve: Microsoft.Bcl.AsyncInterfaces: Resolved from cache. +TpTrace Verbose: 0 : 48056, 2, 2026/06/19, 13:41:29.938, 6199774051246, vstest.console.dll, CurrentDomainAssemblyResolve: Resolving assembly 'Microsoft.Bcl.AsyncInterfaces'. +TpTrace Verbose: 0 : 48056, 2, 2026/06/19, 13:41:29.938, 6199774051439, vstest.console.dll, CurrentDomainAssemblyResolve: Failed to resolve assembly 'Microsoft.Bcl.AsyncInterfaces'. +TpTrace Warning: 0 : 48056, 2, 2026/06/19, 13:41:29.950, 6199774165283, vstest.console.dll, TestPluginDiscoverer: Failed to get types from assembly 'Microsoft.Diagnostics.NETCore.Client, Version=0.2.14.27133, Culture=neutral, PublicKeyToken=31bf3856ad364e35'. Error: System.Reflection.ReflectionTypeLoadException: Unable to load one or more of the requested types. +Could not load file or assembly 'Microsoft.Bcl.AsyncInterfaces, Version=9.0.0.8, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51'. The system cannot find the file specified. +Could not load file or assembly 'Microsoft.Bcl.AsyncInterfaces, Version=9.0.0.8, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51'. The system cannot find the file specified. +Could not load file or assembly 'Microsoft.Bcl.AsyncInterfaces, Version=9.0.0.8, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51'. The system cannot find the file specified. + at System.Reflection.RuntimeModule.GetDefinedTypes() + at System.Reflection.RuntimeModule.GetTypes() + at Microsoft.VisualStudio.TestPlatform.Common.ExtensionFramework.TestPluginDiscoverer.GetTestExtensionsFromAssembly[TPluginInfo,TExtension](Assembly assembly, Dictionary`2 pluginInfos, String filePath) in /_/src/vstest/src/Microsoft.TestPlatform.Common/ExtensionFramework/TestPluginDiscoverer.cs:line 159 +System.IO.FileNotFoundException: Could not load file or assembly 'Microsoft.Bcl.AsyncInterfaces, Version=9.0.0.8, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51'. The system cannot find the file specified. +File name: 'Microsoft.Bcl.AsyncInterfaces, Version=9.0.0.8, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51' + ---> System.IO.FileNotFoundException: Could not load file or assembly 'Microsoft.Bcl.AsyncInterfaces, Culture=neutral, PublicKeyToken=null'. The system cannot find the file specified. +File name: 'Microsoft.Bcl.AsyncInterfaces, Culture=neutral, PublicKeyToken=null' + at System.Reflection.RuntimeAssembly.InternalLoad(AssemblyName assemblyName, StackCrawlMark& stackMark, AssemblyLoadContext assemblyLoadContext, RuntimeAssembly requestingAssembly, Boolean throwOnFileNotFound) + at System.Reflection.Assembly.Load(AssemblyName assemblyRef) + at Microsoft.VisualStudio.TestPlatform.Common.ExtensionFramework.TestPluginCache.CurrentDomainAssemblyResolve(Object sender, AssemblyResolveEventArgs args) in /_/src/vstest/src/Microsoft.TestPlatform.Common/ExtensionFramework/TestPluginCache.cs:line 514 + at System.Runtime.Loader.AssemblyLoadContext.GetFirstResolvedAssemblyFromResolvingEvent(AssemblyName assemblyName) + at System.Runtime.Loader.AssemblyLoadContext.ResolveUsingEvent(AssemblyName assemblyName) +System.IO.FileNotFoundException: Could not load file or assembly 'Microsoft.Bcl.AsyncInterfaces, Version=9.0.0.8, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51'. The system cannot find the file specified. +File name: 'Microsoft.Bcl.AsyncInterfaces, Version=9.0.0.8, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51' +System.IO.FileNotFoundException: Could not load file or assembly 'Microsoft.Bcl.AsyncInterfaces, Version=9.0.0.8, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51'. The system cannot find the file specified. +File name: 'Microsoft.Bcl.AsyncInterfaces, Version=9.0.0.8, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51' +TpTrace Warning: 0 : 48056, 2, 2026/06/19, 13:41:29.950, 6199774169795, vstest.console.dll, LoaderExceptions: System.IO.FileNotFoundException: Could not load file or assembly 'Microsoft.Bcl.AsyncInterfaces, Version=9.0.0.8, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51'. The system cannot find the file specified. +File name: 'Microsoft.Bcl.AsyncInterfaces, Version=9.0.0.8, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51' + ---> System.IO.FileNotFoundException: Could not load file or assembly 'Microsoft.Bcl.AsyncInterfaces, Culture=neutral, PublicKeyToken=null'. The system cannot find the file specified. +File name: 'Microsoft.Bcl.AsyncInterfaces, Culture=neutral, PublicKeyToken=null' + at System.Reflection.RuntimeAssembly.InternalLoad(AssemblyName assemblyName, StackCrawlMark& stackMark, AssemblyLoadContext assemblyLoadContext, RuntimeAssembly requestingAssembly, Boolean throwOnFileNotFound) + at System.Reflection.Assembly.Load(AssemblyName assemblyRef) + at Microsoft.VisualStudio.TestPlatform.Common.ExtensionFramework.TestPluginCache.CurrentDomainAssemblyResolve(Object sender, AssemblyResolveEventArgs args) in /_/src/vstest/src/Microsoft.TestPlatform.Common/ExtensionFramework/TestPluginCache.cs:line 514 + at System.Runtime.Loader.AssemblyLoadContext.GetFirstResolvedAssemblyFromResolvingEvent(AssemblyName assemblyName) + at System.Runtime.Loader.AssemblyLoadContext.ResolveUsingEvent(AssemblyName assemblyName) +TpTrace Warning: 0 : 48056, 2, 2026/06/19, 13:41:29.950, 6199774170475, vstest.console.dll, LoaderExceptions: System.IO.FileNotFoundException: Could not load file or assembly 'Microsoft.Bcl.AsyncInterfaces, Version=9.0.0.8, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51'. The system cannot find the file specified. +File name: 'Microsoft.Bcl.AsyncInterfaces, Version=9.0.0.8, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51' +TpTrace Warning: 0 : 48056, 2, 2026/06/19, 13:41:29.950, 6199774170873, vstest.console.dll, LoaderExceptions: System.IO.FileNotFoundException: Could not load file or assembly 'Microsoft.Bcl.AsyncInterfaces, Version=9.0.0.8, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51'. The system cannot find the file specified. +File name: 'Microsoft.Bcl.AsyncInterfaces, Version=9.0.0.8, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51' +TpTrace Information: 0 : 48056, 2, 2026/06/19, 13:41:29.950, 6199774171936, vstest.console.dll, AssemblyResolver.OnResolve: Microsoft.TestPlatform.Extensions.BlameDataCollector: Resolving assembly. +TpTrace Information: 0 : 48056, 2, 2026/06/19, 13:41:29.951, 6199774172406, vstest.console.dll, AssemblyResolver.OnResolve: Microsoft.TestPlatform.Extensions.BlameDataCollector: Searching in: 'C:\Program Files\dotnet\sdk\10.0.301\Extensions'. +TpTrace Information: 0 : 48056, 2, 2026/06/19, 13:41:29.951, 6199774179701, vstest.console.dll, AssemblyResolver.OnResolve: Microsoft.TestPlatform.Extensions.BlameDataCollector: Loading assembly 'C:\Program Files\dotnet\sdk\10.0.301\Extensions\Microsoft.TestPlatform.Extensions.BlameDataCollector.dll'. +TpTrace Information: 0 : 48056, 2, 2026/06/19, 13:41:29.952, 6199774186601, vstest.console.dll, AssemblyResolver.TrackProvidedDependency: Resolved 'Microsoft.TestPlatform.Extensions.BlameDataCollector' from 'C:\Program Files\dotnet\sdk\10.0.301\Extensions' for 'unknown'. +TpTrace Information: 0 : 48056, 2, 2026/06/19, 13:41:29.952, 6199774187054, vstest.console.dll, AssemblyResolver.OnResolve: Resolved assembly: Microsoft.TestPlatform.Extensions.BlameDataCollector, from path: C:\Program Files\dotnet\sdk\10.0.301\Extensions\Microsoft.TestPlatform.Extensions.BlameDataCollector.dll +TpTrace Verbose: 0 : 48056, 2, 2026/06/19, 13:41:29.952, 6199774188016, vstest.console.dll, MetadataReaderExtensionsHelper: Discovering extensions inside assembly 'Microsoft.TestPlatform.Extensions.BlameDataCollector, Version=15.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' file path 'C:\Program Files\dotnet\sdk\10.0.301\Extensions\Microsoft.TestPlatform.Extensions.BlameDataCollector.dll' +TpTrace Information: 0 : 48056, 2, 2026/06/19, 13:41:29.954, 6199774203822, vstest.console.dll, AssemblyResolver.OnResolve: Microsoft.TestPlatform.Extensions.EventLogCollector: Resolving assembly. +TpTrace Information: 0 : 48056, 2, 2026/06/19, 13:41:29.954, 6199774204404, vstest.console.dll, AssemblyResolver.OnResolve: Microsoft.TestPlatform.Extensions.EventLogCollector: Searching in: 'C:\Program Files\dotnet\sdk\10.0.301\Extensions'. +TpTrace Information: 0 : 48056, 2, 2026/06/19, 13:41:29.954, 6199774208759, vstest.console.dll, AssemblyResolver.OnResolve: Microsoft.TestPlatform.Extensions.EventLogCollector: Loading assembly 'C:\Program Files\dotnet\sdk\10.0.301\Extensions\Microsoft.TestPlatform.Extensions.EventLogCollector.dll'. +TpTrace Information: 0 : 48056, 2, 2026/06/19, 13:41:29.955, 6199774213408, vstest.console.dll, AssemblyResolver.TrackProvidedDependency: Resolved 'Microsoft.TestPlatform.Extensions.EventLogCollector' from 'C:\Program Files\dotnet\sdk\10.0.301\Extensions' for 'unknown'. +TpTrace Information: 0 : 48056, 2, 2026/06/19, 13:41:29.955, 6199774213808, vstest.console.dll, AssemblyResolver.OnResolve: Resolved assembly: Microsoft.TestPlatform.Extensions.EventLogCollector, from path: C:\Program Files\dotnet\sdk\10.0.301\Extensions\Microsoft.TestPlatform.Extensions.EventLogCollector.dll +TpTrace Verbose: 0 : 48056, 2, 2026/06/19, 13:41:29.955, 6199774214674, vstest.console.dll, MetadataReaderExtensionsHelper: Discovering extensions inside assembly 'Microsoft.TestPlatform.Extensions.EventLogCollector, Version=15.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' file path 'C:\Program Files\dotnet\sdk\10.0.301\Extensions\Microsoft.TestPlatform.Extensions.EventLogCollector.dll' +TpTrace Information: 0 : 48056, 2, 2026/06/19, 13:41:29.957, 6199774237688, vstest.console.dll, AssemblyResolver.OnResolve: Microsoft.TestPlatform.TestHostRuntimeProvider: Resolving assembly. +TpTrace Information: 0 : 48056, 2, 2026/06/19, 13:41:29.957, 6199774238279, vstest.console.dll, AssemblyResolver.OnResolve: Microsoft.TestPlatform.TestHostRuntimeProvider: Searching in: 'C:\Program Files\dotnet\sdk\10.0.301\Extensions'. +TpTrace Information: 0 : 48056, 2, 2026/06/19, 13:41:29.958, 6199774242150, vstest.console.dll, AssemblyResolver.OnResolve: Microsoft.TestPlatform.TestHostRuntimeProvider: Loading assembly 'C:\Program Files\dotnet\sdk\10.0.301\Extensions\Microsoft.TestPlatform.TestHostRuntimeProvider.dll'. +TpTrace Information: 0 : 48056, 2, 2026/06/19, 13:41:29.958, 6199774246864, vstest.console.dll, AssemblyResolver.TrackProvidedDependency: Resolved 'Microsoft.TestPlatform.TestHostRuntimeProvider' from 'C:\Program Files\dotnet\sdk\10.0.301\Extensions' for 'unknown'. +TpTrace Information: 0 : 48056, 2, 2026/06/19, 13:41:29.958, 6199774247278, vstest.console.dll, AssemblyResolver.OnResolve: Resolved assembly: Microsoft.TestPlatform.TestHostRuntimeProvider, from path: C:\Program Files\dotnet\sdk\10.0.301\Extensions\Microsoft.TestPlatform.TestHostRuntimeProvider.dll +TpTrace Verbose: 0 : 48056, 2, 2026/06/19, 13:41:29.958, 6199774247658, vstest.console.dll, MetadataReaderExtensionsHelper: Discovering extensions inside assembly 'Microsoft.TestPlatform.TestHostRuntimeProvider, Version=15.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' file path 'C:\Program Files\dotnet\sdk\10.0.301\Extensions\Microsoft.TestPlatform.TestHostRuntimeProvider.dll' +TpTrace Information: 0 : 48056, 2, 2026/06/19, 13:41:29.960, 6199774262780, vstest.console.dll, GetTestExtensionFromType: Register extension with identifier data 'HostProvider://DefaultTestHost' and type 'Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.Hosting.DefaultTestHostManager, Microsoft.TestPlatform.TestHostRuntimeProvider, Version=15.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' inside file 'C:\Program Files\dotnet\sdk\10.0.301\Extensions\Microsoft.TestPlatform.TestHostRuntimeProvider.dll' +TpTrace Information: 0 : 48056, 2, 2026/06/19, 13:41:29.960, 6199774266340, vstest.console.dll, GetTestExtensionFromType: Register extension with identifier data 'HostProvider://DotnetTestHost' and type 'Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.Hosting.DotnetTestHostManager, Microsoft.TestPlatform.TestHostRuntimeProvider, Version=15.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' inside file 'C:\Program Files\dotnet\sdk\10.0.301\Extensions\Microsoft.TestPlatform.TestHostRuntimeProvider.dll' +TpTrace Information: 0 : 48056, 2, 2026/06/19, 13:41:29.960, 6199774267549, vstest.console.dll, AssemblyResolver.OnResolve: Microsoft.VisualStudio.TestPlatform.Extensions.Html.TestLogger: Resolving assembly. +TpTrace Information: 0 : 48056, 2, 2026/06/19, 13:41:29.960, 6199774268074, vstest.console.dll, AssemblyResolver.OnResolve: Microsoft.VisualStudio.TestPlatform.Extensions.Html.TestLogger: Searching in: 'C:\Program Files\dotnet\sdk\10.0.301\Extensions'. +TpTrace Information: 0 : 48056, 2, 2026/06/19, 13:41:29.961, 6199774273417, vstest.console.dll, AssemblyResolver.OnResolve: Microsoft.VisualStudio.TestPlatform.Extensions.Html.TestLogger: Loading assembly 'C:\Program Files\dotnet\sdk\10.0.301\Extensions\Microsoft.VisualStudio.TestPlatform.Extensions.Html.TestLogger.dll'. +TpTrace Information: 0 : 48056, 2, 2026/06/19, 13:41:29.961, 6199774278803, vstest.console.dll, AssemblyResolver.TrackProvidedDependency: Resolved 'Microsoft.VisualStudio.TestPlatform.Extensions.Html.TestLogger' from 'C:\Program Files\dotnet\sdk\10.0.301\Extensions' for 'unknown'. +TpTrace Information: 0 : 48056, 2, 2026/06/19, 13:41:29.961, 6199774279258, vstest.console.dll, AssemblyResolver.OnResolve: Resolved assembly: Microsoft.VisualStudio.TestPlatform.Extensions.Html.TestLogger, from path: C:\Program Files\dotnet\sdk\10.0.301\Extensions\Microsoft.VisualStudio.TestPlatform.Extensions.Html.TestLogger.dll +TpTrace Verbose: 0 : 48056, 2, 2026/06/19, 13:41:29.961, 6199774279701, vstest.console.dll, MetadataReaderExtensionsHelper: Discovering extensions inside assembly 'Microsoft.VisualStudio.TestPlatform.Extensions.Html.TestLogger, Version=15.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' file path 'C:\Program Files\dotnet\sdk\10.0.301\Extensions\Microsoft.VisualStudio.TestPlatform.Extensions.Html.TestLogger.dll' +TpTrace Information: 0 : 48056, 2, 2026/06/19, 13:41:29.962, 6199774287533, vstest.console.dll, AssemblyResolver.OnResolve: Microsoft.VisualStudio.TestPlatform.Extensions.Trx.TestLogger: Resolving assembly. +TpTrace Information: 0 : 48056, 2, 2026/06/19, 13:41:29.962, 6199774288031, vstest.console.dll, AssemblyResolver.OnResolve: Microsoft.VisualStudio.TestPlatform.Extensions.Trx.TestLogger: Searching in: 'C:\Program Files\dotnet\sdk\10.0.301\Extensions'. +TpTrace Information: 0 : 48056, 2, 2026/06/19, 13:41:29.962, 6199774291554, vstest.console.dll, AssemblyResolver.OnResolve: Microsoft.VisualStudio.TestPlatform.Extensions.Trx.TestLogger: Loading assembly 'C:\Program Files\dotnet\sdk\10.0.301\Extensions\Microsoft.VisualStudio.TestPlatform.Extensions.Trx.TestLogger.dll'. +TpTrace Information: 0 : 48056, 2, 2026/06/19, 13:41:29.963, 6199774297880, vstest.console.dll, AssemblyResolver.TrackProvidedDependency: Resolved 'Microsoft.VisualStudio.TestPlatform.Extensions.Trx.TestLogger' from 'C:\Program Files\dotnet\sdk\10.0.301\Extensions' for 'unknown'. +TpTrace Information: 0 : 48056, 2, 2026/06/19, 13:41:29.963, 6199774298381, vstest.console.dll, AssemblyResolver.OnResolve: Resolved assembly: Microsoft.VisualStudio.TestPlatform.Extensions.Trx.TestLogger, from path: C:\Program Files\dotnet\sdk\10.0.301\Extensions\Microsoft.VisualStudio.TestPlatform.Extensions.Trx.TestLogger.dll +TpTrace Verbose: 0 : 48056, 2, 2026/06/19, 13:41:29.963, 6199774298935, vstest.console.dll, MetadataReaderExtensionsHelper: Discovering extensions inside assembly 'Microsoft.VisualStudio.TestPlatform.Extensions.Trx.TestLogger, Version=15.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' file path 'C:\Program Files\dotnet\sdk\10.0.301\Extensions\Microsoft.VisualStudio.TestPlatform.Extensions.Trx.TestLogger.dll' +TpTrace Verbose: 0 : 48056, 2, 2026/06/19, 13:41:29.964, 6199774311946, vstest.console.dll, TestPluginCache: Discovered the extensions using extension path ''. +TpTrace Verbose: 0 : 48056, 2, 2026/06/19, 13:41:29.965, 6199774313184, vstest.console.dll, TestPluginCache: Discoverers are ''. +TpTrace Verbose: 0 : 48056, 2, 2026/06/19, 13:41:29.965, 6199774313509, vstest.console.dll, TestPluginCache: Executors are ''. +TpTrace Verbose: 0 : 48056, 2, 2026/06/19, 13:41:29.965, 6199774313727, vstest.console.dll, TestPluginCache: Executors2 are ''. +TpTrace Verbose: 0 : 48056, 2, 2026/06/19, 13:41:29.965, 6199774313875, vstest.console.dll, TestPluginCache: Setting providers are ''. +TpTrace Verbose: 0 : 48056, 2, 2026/06/19, 13:41:29.965, 6199774314009, vstest.console.dll, TestPluginCache: Loggers are ''. +TpTrace Verbose: 0 : 48056, 2, 2026/06/19, 13:41:29.965, 6199774315840, vstest.console.dll, TestPluginCache: TestHosts are 'HostProvider://DefaultTestHost,HostProvider://DotnetTestHost'. +TpTrace Verbose: 0 : 48056, 2, 2026/06/19, 13:41:29.965, 6199774316242, vstest.console.dll, TestPluginCache: DataCollectors are ''. +TpTrace Information: 0 : 48056, 2, 2026/06/19, 13:41:29.978, 6199774443544, vstest.console.dll, RunTestsArgumentProcessor:Execute: Test run is starting. +TpTrace Verbose: 0 : 48056, 2, 2026/06/19, 13:41:29.978, 6199774444628, vstest.console.dll, RunTestsArgumentProcessor:Execute: Queuing Test run. +TpTrace Information: 0 : 48056, 2, 2026/06/19, 13:41:29.978, 6199774446784, vstest.console.dll, TestRequestManager.RunTests: run tests started. +TpTrace Information: 0 : 48056, 2, 2026/06/19, 13:41:29.979, 6199774457785, vstest.console.dll, AssemblyMetadataProvider.GetFrameworkName: Determined framework:'.NETCoreApp,Version=v10.0' for source: 'D:\Projects\TransactionProcessing\EstateManagementUI\EstateManagementUI.IntegrationTests\bin\Debug\net10.0\EstateManagementUI.IntegrationTests.dll' +TpTrace Information: 0 : 48056, 2, 2026/06/19, 13:41:29.979, 6199774458842, vstest.console.dll, Determined framework for all sources: .NETCoreApp,Version=v10.0 +TpTrace Verbose: 0 : 48056, 2, 2026/06/19, 13:41:29.981, 6199774473360, vstest.console.dll, TestRequestManager.UpdateRunSettingsIfRequired: Default architecture: X64 IsDefaultTargetArchitecture: True, Current process architecture: X64 OperatingSystem: Windows. +TpTrace Information: 0 : 48056, 2, 2026/06/19, 13:41:29.982, 6199774490084, vstest.console.dll, AssemblyMetadataProvider.GetArchitecture: Determined architecture:AnyCPU info for assembly: D:\Projects\TransactionProcessing\EstateManagementUI\EstateManagementUI.IntegrationTests\bin\Debug\net10.0\EstateManagementUI.IntegrationTests.dll +TpTrace Information: 0 : 48056, 2, 2026/06/19, 13:41:29.982, 6199774490685, vstest.console.dll, Determined platform for source 'D:\Projects\TransactionProcessing\EstateManagementUI\EstateManagementUI.IntegrationTests\bin\Debug\net10.0\EstateManagementUI.IntegrationTests.dll' was AnyCPU and it will use the default plaform X64. +TpTrace Information: 0 : 48056, 2, 2026/06/19, 13:41:29.982, 6199774490896, vstest.console.dll, None of the sources provided any runnable platform, using the default platform: X64 +TpTrace Information: 0 : 48056, 2, 2026/06/19, 13:41:29.983, 6199774492315, vstest.console.dll, Platform was updated to 'X64'. +TpTrace Information: 0 : 48056, 2, 2026/06/19, 13:41:29.985, 6199774517686, vstest.console.dll, Compatible sources list: +TpTrace Information: 0 : 48056, 2, 2026/06/19, 13:41:29.985, 6199774518511, vstest.console.dll, D:\Projects\TransactionProcessing\EstateManagementUI\EstateManagementUI.IntegrationTests\bin\Debug\net10.0\EstateManagementUI.IntegrationTests.dll +TpTrace Information: 0 : 48056, 2, 2026/06/19, 13:41:29.988, 6199774551188, vstest.console.dll, InferRunSettingsHelper.IsTestSettingsEnabled: Unable to navigate to RunSettings/MSTest. Current node: RunSettings +TpTrace Information: 0 : 48056, 2, 2026/06/19, 13:41:29.989, 6199774559460, vstest.console.dll, AssemblyResolver.OnResolve: Microsoft.VisualStudio.TestPlatform.Fakes: Resolving assembly. +TpTrace Information: 0 : 48056, 2, 2026/06/19, 13:41:29.989, 6199774559991, vstest.console.dll, AssemblyResolver.OnResolve: Microsoft.VisualStudio.TestPlatform.Fakes: Searching in: 'C:\Program Files\dotnet\sdk\10.0.301\Extensions'. +TpTrace Information: 0 : 48056, 2, 2026/06/19, 13:41:29.989, 6199774560739, vstest.console.dll, AssemblyResolver.OnResolve: Microsoft.VisualStudio.TestPlatform.Fakes: Assembly path does not exist: 'C:\Program Files\dotnet\sdk\10.0.301\Extensions\Microsoft.VisualStudio.TestPlatform.Fakes.dll', returning. +TpTrace Information: 0 : 48056, 2, 2026/06/19, 13:41:29.989, 6199774561487, vstest.console.dll, AssemblyResolver.OnResolve: Microsoft.VisualStudio.TestPlatform.Fakes: Assembly path does not exist: 'C:\Program Files\dotnet\sdk\10.0.301\Extensions\Microsoft.VisualStudio.TestPlatform.Fakes.exe', returning. +TpTrace Information: 0 : 48056, 2, 2026/06/19, 13:41:29.989, 6199774561858, vstest.console.dll, AssemblyResolver.OnResolve: Microsoft.VisualStudio.TestPlatform.Fakes: Searching in: 'C:\Program Files\dotnet\sdk\10.0.301'. +TpTrace Information: 0 : 48056, 2, 2026/06/19, 13:41:29.990, 6199774562402, vstest.console.dll, AssemblyResolver.OnResolve: Microsoft.VisualStudio.TestPlatform.Fakes: Assembly path does not exist: 'C:\Program Files\dotnet\sdk\10.0.301\Microsoft.VisualStudio.TestPlatform.Fakes.dll', returning. +TpTrace Information: 0 : 48056, 2, 2026/06/19, 13:41:29.990, 6199774562871, vstest.console.dll, AssemblyResolver.OnResolve: Microsoft.VisualStudio.TestPlatform.Fakes: Assembly path does not exist: 'C:\Program Files\dotnet\sdk\10.0.301\Microsoft.VisualStudio.TestPlatform.Fakes.exe', returning. +TpTrace Information: 0 : 48056, 2, 2026/06/19, 13:41:29.990, 6199774563096, vstest.console.dll, AssemblyResolver.OnResolve: Microsoft.VisualStudio.TestPlatform.Fakes: Failed to load assembly. +TpTrace Information: 0 : 48056, 2, 2026/06/19, 13:41:29.990, 6199774565604, vstest.console.dll, Failed to load assembly Microsoft.VisualStudio.TestPlatform.Fakes, Version=18.0.0.0, Culture=neutral. Reason:System.IO.FileNotFoundException: Could not load file or assembly 'Microsoft.VisualStudio.TestPlatform.Fakes, Version=18.0.0.0, Culture=neutral, PublicKeyToken=null'. The system cannot find the file specified. +File name: 'Microsoft.VisualStudio.TestPlatform.Fakes, Version=18.0.0.0, Culture=neutral, PublicKeyToken=null' + at System.Reflection.RuntimeAssembly.InternalLoad(AssemblyName assemblyName, StackCrawlMark& stackMark, AssemblyLoadContext assemblyLoadContext, RuntimeAssembly requestingAssembly, Boolean throwOnFileNotFound) + at System.Reflection.Assembly.Load(AssemblyName assemblyRef) + at Microsoft.VisualStudio.TestPlatform.Common.Utilities.FakesUtilities.LoadTestPlatformAssembly() in /_/src/vstest/src/Microsoft.TestPlatform.Common/Utilities/FakesUtilities.cs:line 200 +TpTrace Verbose: 0 : 48056, 2, 2026/06/19, 13:41:29.991, 6199774577115, vstest.console.dll, TestPluginCache: Update extensions started. Skip filter = False +TpTrace Verbose: 0 : 48056, 2, 2026/06/19, 13:41:29.993, 6199774595556, vstest.console.dll, TestPluginCache: Using directories for assembly resolution 'C:\Users\stuar\.nuget\packages\coverlet.collector\10.0.1\build\net10.0'. +TpTrace Verbose: 0 : 48056, 2, 2026/06/19, 13:41:29.993, 6199774596285, vstest.console.dll, TestPluginCache: Updated the available extensions to 'C:\Users\stuar\.nuget\packages\coverlet.collector\10.0.1\build\net10.0\coverlet.collector.dll'. +TpTrace Verbose: 0 : 48056, 2, 2026/06/19, 13:41:30.005, 6199774715176, vstest.console.dll, TestEngine: Initializing Parallel Execution as MaxCpuCount is set to: 1 +TpTrace Information: 0 : 48056, 2, 2026/06/19, 13:41:30.006, 6199774726963, vstest.console.dll, TestPluginManager.CreateTestExtension: Attempting to load test extension: Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.Hosting.DefaultTestHostManager +TpTrace Information: 0 : 48056, 2, 2026/06/19, 13:41:30.007, 6199774734571, vstest.console.dll, TestPluginManager.CreateTestExtension: Attempting to load test extension: Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.Hosting.DotnetTestHostManager +TpTrace Verbose: 0 : 48056, 2, 2026/06/19, 13:41:30.007, 6199774737134, vstest.console.dll, TestHostManagerCallbacks.ctor: Forwarding output is enabled. +TpTrace Information: 0 : 48056, 2, 2026/06/19, 13:41:30.007, 6199774741151, vstest.console.dll, InferRunSettingsHelper.IsTestSettingsEnabled: Unable to navigate to RunSettings/MSTest. Current node: RunSettings +TpTrace Verbose: 0 : 48056, 2, 2026/06/19, 13:41:30.008, 6199774746258, vstest.console.dll, ParallelOperationManager.ClearSlots: Clearing all slots. Slots should accept more work: True +TpTrace Verbose: 0 : 48056, 2, 2026/06/19, 13:41:30.009, 6199774760014, vstest.console.dll, ParallelOperationManager.SetOccupiedSlotCount: Setting slot counts AvailableSlotCount = 1, OccupiedSlotCount = 0. +TpTrace Verbose: 0 : 48056, 2, 2026/06/19, 13:41:30.010, 6199774763657, vstest.console.dll, Occupied slots: + +TpTrace Verbose: 0 : 48056, 2, 2026/06/19, 13:41:30.014, 6199774804839, vstest.console.dll, TestEngine.GetExecutionManager: Chosen execution manager 'Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.Client.Parallel.ParallelProxyExecutionManager, Microsoft.TestPlatform.CrossPlatEngine, Version=15.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' ParallelLevel '1'. +TpTrace Verbose: 0 : 48056, 2, 2026/06/19, 13:41:30.014, 6199774807103, vstest.console.dll, TestPlatform.GetSkipDefaultAdapters: Not skipping default adapters SkipDefaultAdapters was false. +TpTrace Verbose: 0 : 48056, 2, 2026/06/19, 13:41:30.014, 6199774808082, vstest.console.dll, TestRunRequest.ExecuteAsync: Creating test run request. +TpTrace Verbose: 0 : 48056, 2, 2026/06/19, 13:41:30.015, 6199774813482, vstest.console.dll, TestRunRequest.ExecuteAsync: Starting. +TpTrace Information: 0 : 48056, 2, 2026/06/19, 13:41:30.015, 6199774816031, vstest.console.dll, TestRunRequest.ExecuteAsync: Starting run with settings:TestRunCriteria: + KeepAlive=False,FrequencyOfRunStatsChangeEvent=10,RunStatsChangeEventTimeout=00:00:01.5000000,TestCaseFilter=FullyQualifiedName~AdministratorsSeeTheDashboardWelcomePanel,TestExecutorLauncher= + Settingsxml= + + D:\Projects\TransactionProcessing\EstateManagementUI\EstateManagementUI.IntegrationTests\TestResults + X64 + .NETCoreApp,Version=v10.0 + C:\Users\stuar\.nuget\packages\coverlet.collector\10.0.1\build\net10.0\ + False + False + + + + + + minimal + + + + + + +TpTrace Verbose: 0 : 48056, 2, 2026/06/19, 13:41:30.015, 6199774816483, vstest.console.dll, TestRunRequest.ExecuteAsync: Wait for the first run request is over. +TpTrace Verbose: 0 : 48056, 2, 2026/06/19, 13:41:30.015, 6199774818817, vstest.console.dll, MulticastDelegateUtilities.SafeInvoke: TestRun.TestRunStart: Invoking callbacks was skipped because there are no subscribers. +TpTrace Verbose: 0 : 48056, 4, 2026/06/19, 13:41:30.015, 6199774821566, vstest.console.dll, MulticastDelegateUtilities.SafeInvoke: InternalTestLoggerEvents.SendTestRunStart: Invoking callback 1/1 for Microsoft.VisualStudio.TestPlatform.CommandLine.Internal.ConsoleLogger., took 0 ms. +TpTrace Verbose: 0 : 48056, 2, 2026/06/19, 13:41:30.016, 6199774828548, vstest.console.dll, ParallelProxyExecutionManager: Start execution. Total sources: 1 +TpTrace Verbose: 0 : 48056, 2, 2026/06/19, 13:41:30.016, 6199774831266, vstest.console.dll, ParallelOperationManager.StartWork: Starting adding 1 workloads. +TpTrace Verbose: 0 : 48056, 2, 2026/06/19, 13:41:30.016, 6199774831980, vstest.console.dll, ParallelOperationManager.ClearSlots: Clearing all slots. Slots should accept more work: True +TpTrace Verbose: 0 : 48056, 2, 2026/06/19, 13:41:30.017, 6199774833247, vstest.console.dll, ParallelOperationManager.SetOccupiedSlotCount: Setting slot counts AvailableSlotCount = 1, OccupiedSlotCount = 0. +TpTrace Verbose: 0 : 48056, 2, 2026/06/19, 13:41:30.017, 6199774833712, vstest.console.dll, Occupied slots: + +TpTrace Verbose: 0 : 48056, 2, 2026/06/19, 13:41:30.018, 6199774849563, vstest.console.dll, TestHostManagerCallbacks.ctor: Forwarding output is enabled. +TpTrace Verbose: 0 : 48056, 2, 2026/06/19, 13:41:30.018, 6199774851954, vstest.console.dll, TestRequestSender is acting as server. +TpTrace Verbose: 0 : 48056, 2, 2026/06/19, 13:41:30.019, 6199774855533, vstest.console.dll, ParallelOperationManager.RunWorkInParallel: Adding 1 workload to slot, remaining workloads 0. +TpTrace Verbose: 0 : 48056, 2, 2026/06/19, 13:41:30.019, 6199774856694, vstest.console.dll, ParallelOperationManager.SetOccupiedSlotCount: Setting slot counts AvailableSlotCount = 0, OccupiedSlotCount = 1. +TpTrace Verbose: 0 : 48056, 2, 2026/06/19, 13:41:30.019, 6199774858010, vstest.console.dll, Occupied slots: +0: D:\Projects\TransactionProcessing\EstateManagementUI\EstateManagementUI.IntegrationTests\bin\Debug\net10.0\EstateManagementUI.IntegrationTests.dll +TpTrace Verbose: 0 : 48056, 2, 2026/06/19, 13:41:30.021, 6199774876695, vstest.console.dll, ParallelOperationManager.RunWorkInParallel: Started host in slot number 0 for work (source): D:\Projects\TransactionProcessing\EstateManagementUI\EstateManagementUI.IntegrationTests\bin\Debug\net10.0\EstateManagementUI.IntegrationTests.dll. +TpTrace Verbose: 0 : 48056, 2, 2026/06/19, 13:41:30.022, 6199774883497, vstest.console.dll, ParallelOperationManager.RunWorkInParallel: We started 1 work items, which is the max parallel level. Won't start more work. +TpTrace Verbose: 0 : 48056, 2, 2026/06/19, 13:41:30.022, 6199774884077, vstest.console.dll, ParallelOperationManager.RunWorkInParallel: We started 1 work items in here, returning True. +TpTrace Information: 0 : 48056, 2, 2026/06/19, 13:41:30.022, 6199774884447, vstest.console.dll, TestRunRequest.ExecuteAsync: Started. +TpTrace Verbose: 0 : 48056, 2, 2026/06/19, 13:41:30.022, 6199774885131, vstest.console.dll, TestRunRequest.WaitForCompletion: Waiting with timeout -1. +TpTrace Verbose: 0 : 48056, 5, 2026/06/19, 13:41:30.022, 6199774889332, vstest.console.dll, ParallelProxyExecutionManager.StartTestRunOnConcurrentManager: Initializing uninitialized client. Started clients: 0 +TpTrace Verbose: 0 : 48056, 5, 2026/06/19, 13:41:30.022, 6199774889966, vstest.console.dll, ParallelProxyExecutionManager.StartTestRunOnConcurrentManager: Initializing test run. Started clients: 0 +TpTrace Verbose: 0 : 48056, 5, 2026/06/19, 13:41:30.022, 6199774890788, vstest.console.dll, ProxyExecutionManager: Test host is always Lazy initialize. +TpTrace Verbose: 0 : 48056, 5, 2026/06/19, 13:41:30.023, 6199774893288, vstest.console.dll, TestRequestSender.InitializeCommunication: initialize communication. +TpTrace Information: 0 : 48056, 5, 2026/06/19, 13:41:30.032, 6199774987775, vstest.console.dll, SocketServer.Start: Listening on endpoint : 127.0.0.1:62255 +TpTrace Verbose: 0 : 48056, 5, 2026/06/19, 13:41:30.037, 6199775041896, vstest.console.dll, DotnetTestHostmanager.GetTestHostProcessStartInfo: Platform environment 'X64' target architecture 'X64' framework '.NETCoreApp,Version=v10.0' OS 'Windows' +TpTrace Verbose: 0 : 48056, 5, 2026/06/19, 13:41:30.038, 6199775043025, vstest.console.dll, DotnetTestHostmanager.LaunchTestHostAsync: VSTEST_DOTNET_ROOT_PATH=C:\Program Files\dotnet +TpTrace Verbose: 0 : 48056, 5, 2026/06/19, 13:41:30.038, 6199775043255, vstest.console.dll, DotnetTestHostmanager.LaunchTestHostAsync: VSTEST_DOTNET_ROOT_ARCHITECTURE=X64 +TpTrace Verbose: 0 : 48056, 5, 2026/06/19, 13:41:30.038, 6199775043797, vstest.console.dll, DotnetTestHostManager.SetDotnetRootForArchitecture: Adding DOTNET_ROOT_X64=C:\Program Files\dotnet to testhost start info. +TpTrace Verbose: 0 : 48056, 5, 2026/06/19, 13:41:30.038, 6199775044941, vstest.console.dll, DotnetTestHostmanager: Adding --runtimeconfig "D:\Projects\TransactionProcessing\EstateManagementUI\EstateManagementUI.IntegrationTests\bin\Debug\net10.0\EstateManagementUI.IntegrationTests.runtimeconfig.json" in args +TpTrace Verbose: 0 : 48056, 5, 2026/06/19, 13:41:30.038, 6199775045433, vstest.console.dll, DotnetTestHostmanager: Adding --depsfile "D:\Projects\TransactionProcessing\EstateManagementUI\EstateManagementUI.IntegrationTests\bin\Debug\net10.0\EstateManagementUI.IntegrationTests.deps.json" in args +TpTrace Verbose: 0 : 48056, 5, 2026/06/19, 13:41:30.038, 6199775046683, vstest.console.dll, DotnetTestHostmanager.IsWinOnArm: Current PROCESSOR_ARCHITECTURE from environment variable 'AMD64' +TpTrace Verbose: 0 : 48056, 5, 2026/06/19, 13:41:30.038, 6199775047102, vstest.console.dll, DotnetTestHostmanager.IsWinOnArm: Is Windows on ARM 'False' +TpTrace Verbose: 0 : 48056, 5, 2026/06/19, 13:41:30.038, 6199775047563, vstest.console.dll, DotnetTestHostManager: testhost.exe found at path: D:\Projects\TransactionProcessing\EstateManagementUI\EstateManagementUI.IntegrationTests\bin\Debug\net10.0\testhost.exe +TpTrace Verbose: 0 : 48056, 5, 2026/06/19, 13:41:30.038, 6199775047827, vstest.console.dll, DotnetTestHostmanager: Full path of host exe is D:\Projects\TransactionProcessing\EstateManagementUI\EstateManagementUI.IntegrationTests\bin\Debug\net10.0\testhost.exe +TpTrace Verbose: 0 : 48056, 5, 2026/06/19, 13:41:30.041, 6199775074490, vstest.console.dll, DotnetTestHostManager: Starting process '0' with command line '1' and DOTNET environment: DOTNET_ROOT_X64=C:\Program Files\dotnet, DOTNET_ROOT=C:\Program Files\dotnet +TpTrace Verbose: 0 : 48056, 5, 2026/06/19, 13:41:30.041, 6199775075077, vstest.console.dll, DotnetTestHostManager: Launching testhost with CreateNoWindow=True +TpTrace Verbose: 0 : 48056, 5, 2026/06/19, 13:41:30.051, 6199775174655, vstest.console.dll, Test Runtime launched +TpTrace Verbose: 0 : 48056, 5, 2026/06/19, 13:41:30.051, 6199775176185, vstest.console.dll, MulticastDelegateUtilities.SafeInvoke: HostProviderEvents.OnHostLaunched: Invoking callback 1/1 for Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.Client.ProxyOperationManager., took 0 ms. +TpTrace Verbose: 0 : 48056, 5, 2026/06/19, 13:41:30.051, 6199775180061, vstest.console.dll, TestRequestSender.WaitForRequestHandlerConnection: waiting for connection with timeout: 90000. +TpTrace Verbose: 0 : 48056, 7, 2026/06/19, 13:41:30.212, 6199776787879, vstest.console.dll, MulticastDelegateUtilities.SafeInvoke: SocketServer: ClientConnected: Invoking callback 1/1 for Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.TestRequestSender., took 0 ms. +TpTrace Verbose: 0 : 48056, 5, 2026/06/19, 13:41:30.212, 6199776787878, vstest.console.dll, TestRequestSender.WaitForRequestHandlerConnection: waiting took 160 ms, with timeout 90000 ms, and result 0, which is success. +TpTrace Verbose: 0 : 48056, 7, 2026/06/19, 13:41:30.212, 6199776789217, vstest.console.dll, SocketServer.OnClientConnected: Client connected for endPoint: 127.0.0.1:62255, starting MessageLoopAsync: +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:41:30.213, 6199776794294, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 0 ms +TpTrace Verbose: 0 : 48056, 5, 2026/06/19, 13:41:30.255, 6199777218052, vstest.console.dll, TestRequestSender.CheckVersionWithTestHost: Sending check version message: {"MessageType":"ProtocolVersion","Payload":7} +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:41:30.369, 6199778355453, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: NotifyDataAvailable remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:41:30.369, 6199778359075, vstest.console.dll, TestRequestSender.CheckVersionWithTestHost: onMessageReceived received message: (ProtocolVersion) -> {"MessageType":"ProtocolVersion","Payload":7} +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:41:30.373, 6199778400266, vstest.console.dll, MulticastDelegateUtilities.SafeInvoke: LengthPrefixCommunicationChannel: MessageReceived: Invoking callback 1/1 for Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.TestRequestSender+<>c__DisplayClass29_0., took 4 ms. +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:41:30.373, 6199778401456, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 160 ms +TpTrace Verbose: 0 : 48056, 5, 2026/06/19, 13:41:30.373, 6199778401623, vstest.console.dll, TestPluginCache.GetExtensionPaths: Filtered extension paths: +TpTrace Verbose: 0 : 48056, 5, 2026/06/19, 13:41:30.374, 6199778402367, vstest.console.dll, TestPluginCache.GetExtensionPaths: Added default extension paths: C:\Program Files\dotnet\sdk\10.0.301\Extensions\Microsoft.Diagnostics.NETCore.Client.dll +C:\Program Files\dotnet\sdk\10.0.301\Extensions\Microsoft.TestPlatform.Extensions.BlameDataCollector.dll +C:\Program Files\dotnet\sdk\10.0.301\Extensions\Microsoft.TestPlatform.Extensions.EventLogCollector.dll +C:\Program Files\dotnet\sdk\10.0.301\Extensions\Microsoft.TestPlatform.TestHostRuntimeProvider.dll +C:\Program Files\dotnet\sdk\10.0.301\Extensions\Microsoft.VisualStudio.TestPlatform.Extensions.Html.TestLogger.dll +C:\Program Files\dotnet\sdk\10.0.301\Extensions\Microsoft.VisualStudio.TestPlatform.Extensions.Trx.TestLogger.dll +TpTrace Verbose: 0 : 48056, 5, 2026/06/19, 13:41:30.374, 6199778402681, vstest.console.dll, TestPluginCache.GetExtensionPaths: Added unfilterableExtensionPaths: +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:41:30.378, 6199778444114, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: NotifyDataAvailable remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 +TpTrace Verbose: 0 : 48056, 5, 2026/06/19, 13:41:30.379, 6199778459468, vstest.console.dll, TestRequestSender.InitializeExecution: Sending initialize execution with message: {"Version":7,"MessageType":"TestExecution.Initialize","Payload":["D:\\Projects\\TransactionProcessing\\EstateManagementUI\\EstateManagementUI.IntegrationTests\\bin\\Debug\\net10.0\\NUnit3.TestAdapter.dll"]} +TpTrace Verbose: 0 : 48056, 5, 2026/06/19, 13:41:30.379, 6199778461229, vstest.console.dll, ParallelProxyExecutionManager.StartTestRunOnConcurrentManager: Execution starting. Started clients: 1 +TpTrace Warning: 0 : 48056, 5, 2026/06/19, 13:41:30.380, 6199778464722, vstest.console.dll, InferRunSettingsHelper.MakeRunsettingsCompatible: Removing the following settings: TargetPlatform from RunSettings file. To use those settings please move to latest version of Microsoft.NET.Test.Sdk +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:41:30.380, 6199778471080, vstest.console.dll, TestRequestSender.OnExecutionMessageReceived: Received message: {"Version":7,"MessageType":"TestSession.Message","Payload":{"MessageLevel":0,"Message":"Logging TestHost Diagnostics in file: D:\\Projects\\TransactionProcessing\\EstateManagementUI\\EstateManagementUI.IntegrationTests\\testdiag.host.26-06-19_13-41-30_03760_5.txt"}} +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:41:30.384, 6199778507330, vstest.console.dll, TestRunRequest:SendTestRunMessage: Starting. +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:41:30.384, 6199778509121, vstest.console.dll, MulticastDelegateUtilities.SafeInvoke: TestRun.LogMessages: Invoking callback 1/1 for Microsoft.VisualStudio.TestPlatform.CommandLine.TestRunResultAggregator., took 0 ms. +TpTrace Information: 0 : 48056, 10, 2026/06/19, 13:41:30.384, 6199778509570, vstest.console.dll, TestRunRequest:SendTestRunMessage: Completed. +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:41:30.384, 6199778510057, vstest.console.dll, MulticastDelegateUtilities.SafeInvoke: LengthPrefixCommunicationChannel: MessageReceived: Invoking callback 1/1 for Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.TestRequestSender+<>c__DisplayClass34_0., took 4 ms. +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:41:30.384, 6199778510538, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 10 ms +TpTrace Verbose: 0 : 48056, 4, 2026/06/19, 13:41:30.384, 6199778511083, vstest.console.dll, MulticastDelegateUtilities.SafeInvoke: InternalTestLoggerEvents.SendTestRunMessage: Invoking callback 1/1 for Microsoft.VisualStudio.TestPlatform.CommandLine.Internal.ConsoleLogger., took 0 ms. +TpTrace Verbose: 0 : 48056, 5, 2026/06/19, 13:41:30.388, 6199778545334, vstest.console.dll, TestRequestSender.StartTestRun: Sending test run with message: {"Version":7,"MessageType":"TestExecution.StartWithSources","Payload":{"AdapterSourceMap":{"_none_":["D:\\Projects\\TransactionProcessing\\EstateManagementUI\\EstateManagementUI.IntegrationTests\\bin\\Debug\\net10.0\\EstateManagementUI.IntegrationTests.dll"]},"RunSettings":"\r\n \r\n D:\\Projects\\TransactionProcessing\\EstateManagementUI\\EstateManagementUI.IntegrationTests\\TestResults\r\n .NETCoreApp,Version=v10.0\r\n C:\\Users\\stuar\\.nuget\\packages\\coverlet.collector\\10.0.1\\build\\net10.0\\\r\n False\r\n False\r\n \r\n \r\n \r\n \r\n \r\n minimal\r\n \r\n \r\n \r\n \r\n","TestExecutionContext":{"FrequencyOfRunStatsChangeEvent":10,"RunStatsChangeEventTimeout":"00:00:01.5000000","InIsolation":false,"KeepAlive":false,"AreTestCaseLevelEventsRequired":false,"IsDebug":false,"TestCaseFilter":"FullyQualifiedName~AdministratorsSeeTheDashboardWelcomePanel","FilterOptions":null},"Package":null}} +TpTrace Verbose: 0 : 48056, 5, 2026/06/19, 13:41:30.388, 6199778547427, vstest.console.dll, ParallelProxyExecutionManager.StartTestRunOnConcurrentManager: Execution started. Started clients: 1 +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:41:30.570, 6199780365589, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: NotifyDataAvailable remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:41:30.570, 6199780366789, vstest.console.dll, TestRequestSender.OnExecutionMessageReceived: Received message: {"Version":7,"MessageType":"TestSession.Message","Payload":{"MessageLevel":0,"Message":"NUnit Adapter 1.0.0.0: Test execution started"}} +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:41:30.570, 6199780368582, vstest.console.dll, TestRunRequest:SendTestRunMessage: Starting. +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:41:30.570, 6199780369175, vstest.console.dll, MulticastDelegateUtilities.SafeInvoke: TestRun.LogMessages: Invoking callback 1/1 for Microsoft.VisualStudio.TestPlatform.CommandLine.TestRunResultAggregator., took 0 ms. +TpTrace Information: 0 : 48056, 10, 2026/06/19, 13:41:30.570, 6199780369422, vstest.console.dll, TestRunRequest:SendTestRunMessage: Completed. +TpTrace Verbose: 0 : 48056, 4, 2026/06/19, 13:41:30.570, 6199780369496, vstest.console.dll, MulticastDelegateUtilities.SafeInvoke: InternalTestLoggerEvents.SendTestRunMessage: Invoking callback 1/1 for Microsoft.VisualStudio.TestPlatform.CommandLine.Internal.ConsoleLogger., took 0 ms. +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:41:30.570, 6199780369623, vstest.console.dll, MulticastDelegateUtilities.SafeInvoke: LengthPrefixCommunicationChannel: MessageReceived: Invoking callback 1/1 for Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.TestRequestSender+<>c__DisplayClass34_0., took 0 ms. +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:41:30.570, 6199780370623, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 185 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:41:30.606, 6199780730468, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: NotifyDataAvailable remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:41:30.606, 6199780731718, vstest.console.dll, TestRequestSender.OnExecutionMessageReceived: Received message: {"Version":7,"MessageType":"TestSession.Message","Payload":{"MessageLevel":0,"Message":"Running selected tests in D:\\Projects\\TransactionProcessing\\EstateManagementUI\\EstateManagementUI.IntegrationTests\\bin\\Debug\\net10.0\\EstateManagementUI.IntegrationTests.dll"}} +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:41:30.607, 6199780732698, vstest.console.dll, TestRunRequest:SendTestRunMessage: Starting. +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:41:30.607, 6199780733151, vstest.console.dll, MulticastDelegateUtilities.SafeInvoke: TestRun.LogMessages: Invoking callback 1/1 for Microsoft.VisualStudio.TestPlatform.CommandLine.TestRunResultAggregator., took 0 ms. +TpTrace Verbose: 0 : 48056, 4, 2026/06/19, 13:41:30.607, 6199780733404, vstest.console.dll, MulticastDelegateUtilities.SafeInvoke: InternalTestLoggerEvents.SendTestRunMessage: Invoking callback 1/1 for Microsoft.VisualStudio.TestPlatform.CommandLine.Internal.ConsoleLogger., took 0 ms. +TpTrace Information: 0 : 48056, 10, 2026/06/19, 13:41:30.607, 6199780733509, vstest.console.dll, TestRunRequest:SendTestRunMessage: Completed. +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:41:30.607, 6199780734983, vstest.console.dll, MulticastDelegateUtilities.SafeInvoke: LengthPrefixCommunicationChannel: MessageReceived: Invoking callback 1/1 for Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.TestRequestSender+<>c__DisplayClass34_0., took 0 ms. +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:41:30.607, 6199780735273, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 36 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:41:30.812, 6199782785614, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: NotifyDataAvailable remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:41:30.812, 6199782787398, vstest.console.dll, TestRequestSender.OnExecutionMessageReceived: Received message: {"Version":7,"MessageType":"TestSession.Message","Payload":{"MessageLevel":0,"Message":" NUnit3TestExecutor discovered 1 of 1 NUnit test cases using Current Discovery mode, Non-Explicit run"}} +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:41:30.812, 6199782788692, vstest.console.dll, TestRunRequest:SendTestRunMessage: Starting. +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:41:30.812, 6199782789363, vstest.console.dll, MulticastDelegateUtilities.SafeInvoke: TestRun.LogMessages: Invoking callback 1/1 for Microsoft.VisualStudio.TestPlatform.CommandLine.TestRunResultAggregator., took 0 ms. +TpTrace Verbose: 0 : 48056, 4, 2026/06/19, 13:41:30.812, 6199782789655, vstest.console.dll, MulticastDelegateUtilities.SafeInvoke: InternalTestLoggerEvents.SendTestRunMessage: Invoking callback 1/1 for Microsoft.VisualStudio.TestPlatform.CommandLine.Internal.ConsoleLogger., took 0 ms. +TpTrace Information: 0 : 48056, 10, 2026/06/19, 13:41:30.812, 6199782789713, vstest.console.dll, TestRunRequest:SendTestRunMessage: Completed. +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:41:30.812, 6199782790837, vstest.console.dll, MulticastDelegateUtilities.SafeInvoke: LengthPrefixCommunicationChannel: MessageReceived: Invoking callback 1/1 for Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.TestRequestSender+<>c__DisplayClass34_0., took 0 ms. +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:41:30.812, 6199782791154, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 205 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:41:31.822, 6199792890504, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1009 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:41:32.147, 6199796135125, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: NotifyDataAvailable remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:41:32.147, 6199796136603, vstest.console.dll, TestRequestSender.OnExecutionMessageReceived: Received message: {"Version":7,"MessageType":"TestExecution.StatsChange","Payload":{"NewTestResults":[],"TestRunStatistics":{"ExecutedTests":0,"Stats":{}},"ActiveTests":[{"Id":"856509a0-37bf-5299-e232-e80e305d4dd4","FullyQualifiedName":"EstateManagementUI.IntegrationTests.Features.DashboardFeature.AdministratorsSeeTheDashboardWelcomePanel","DisplayName":"AdministratorsSeeTheDashboardWelcomePanel","ExecutorUri":"executor://NUnit3TestExecutor","Source":"D:\\Projects\\TransactionProcessing\\EstateManagementUI\\EstateManagementUI.IntegrationTests\\bin\\Debug\\net10.0\\EstateManagementUI.IntegrationTests.dll","CodeFilePath":null,"LineNumber":0,"Properties":[{"Key":{"Id":"NUnit.TestCategory","Label":"TestCategory","Category":"","Description":"","Attributes":5,"ValueType":"System.String[]"},"Value":["base","background","dashboard","Dashboard","AdministratorRole"]},{"Key":{"Id":"NUnit.Seed","Label":"Seed","Category":"","Description":"","Attributes":0,"ValueType":"System.String"},"Value":"1743199602"}]}]}} +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:41:32.173, 6199796395052, vstest.console.dll, TestRunRequest:SendTestRunStatsChange: Starting. +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:41:32.173, 6199796396287, vstest.console.dll, InProgress is AdministratorsSeeTheDashboardWelcomePanel +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:41:32.173, 6199796397113, vstest.console.dll, MulticastDelegateUtilities.SafeInvoke: TestRun.RunStatsChanged: Invoking callbacks was skipped because there are no subscribers. +TpTrace Information: 0 : 48056, 10, 2026/06/19, 13:41:32.173, 6199796397441, vstest.console.dll, TestRunRequest:SendTestRunStatsChange: Completed. +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:41:32.173, 6199796397721, vstest.console.dll, MulticastDelegateUtilities.SafeInvoke: LengthPrefixCommunicationChannel: MessageReceived: Invoking callback 1/1 for Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.TestRequestSender+<>c__DisplayClass34_0., took 26 ms. +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:41:32.173, 6199796397965, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 350 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:41:33.180, 6199806470427, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1007 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:41:34.188, 6199816542099, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1006 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:41:35.203, 6199826693855, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1015 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:41:36.208, 6199836747382, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1005 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:41:37.212, 6199846790083, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1004 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:41:38.221, 6199856872803, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1008 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:41:39.228, 6199866946386, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1007 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:41:40.235, 6199877019710, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1007 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:41:41.245, 6199887119542, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1009 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:41:42.255, 6199897220235, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1009 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:41:43.264, 6199907303243, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1008 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:41:44.266, 6199917331337, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1002 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:41:45.275, 6199927421211, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1008 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:41:46.282, 6199937483585, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1006 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:41:47.285, 6199947512624, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1002 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:41:48.289, 6199957558304, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1004 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:41:49.295, 6199967619333, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1005 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:41:50.303, 6199977695470, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1007 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:41:51.316, 6199987822769, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1012 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:41:52.319, 6199997861080, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1003 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:41:53.335, 6200008015072, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1015 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:41:54.346, 6200018126224, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1010 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:41:55.351, 6200028173989, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1004 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:41:56.364, 6200038309645, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1013 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:41:57.375, 6200048418207, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1010 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:41:58.379, 6200058456238, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1003 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:41:59.389, 6200068554116, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1009 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:42:00.391, 6200078579132, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1002 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:42:01.405, 6200088717584, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1013 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:42:02.406, 6200098725589, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1000 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:42:03.420, 6200108863699, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1013 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:42:04.424, 6200118903960, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1003 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:42:05.428, 6200128944222, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1003 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:42:06.440, 6200139063761, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1011 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:42:07.450, 6200149163911, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1009 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:42:08.459, 6200159253159, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1008 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:42:09.472, 6200169384774, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1013 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:42:10.482, 6200179486247, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1010 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:42:11.486, 6200189528853, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1004 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:42:12.497, 6200199637142, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1010 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:42:13.505, 6200209714616, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1007 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:42:14.513, 6200219795081, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1007 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:42:15.517, 6200229833178, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1003 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:42:16.531, 6200239980769, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1014 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:42:17.538, 6200250050962, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1006 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:42:18.544, 6200260111951, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1005 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:42:19.554, 6200270211377, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1009 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:42:20.560, 6200280268572, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1005 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:42:21.572, 6200290388142, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1011 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:42:22.581, 6200300478959, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1008 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:42:23.589, 6200310557132, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1007 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:42:24.602, 6200320688120, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1012 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:42:25.617, 6200330840700, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1015 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:42:26.633, 6200340992909, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1015 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:42:27.646, 6200351127077, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1013 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:42:28.656, 6200361227374, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1009 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:42:29.658, 6200371247937, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1001 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:42:30.663, 6200381298568, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1004 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:42:31.678, 6200391442773, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1014 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:42:32.686, 6200401531779, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1008 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:42:33.688, 6200411542765, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1000 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:42:34.689, 6200421560543, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1001 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:42:35.703, 6200431701125, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1013 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:42:36.713, 6200441795856, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1009 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:42:37.716, 6200451826869, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1002 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:42:38.730, 6200461968003, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1013 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:42:39.743, 6200472098741, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1012 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:42:40.755, 6200482221495, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1012 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:42:41.762, 6200492286500, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1006 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:42:42.770, 6200502363028, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1007 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:42:43.771, 6200512380368, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1001 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:42:44.773, 6200522399859, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1001 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:42:45.779, 6200532458449, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1005 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:42:46.785, 6200542513081, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1005 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:42:47.790, 6200552568930, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1005 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:42:48.799, 6200562659222, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1008 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:42:49.807, 6200572733121, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1007 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:42:50.815, 6200582813381, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1007 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:42:51.815, 6200592821071, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1000 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:42:52.818, 6200602845082, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1002 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:42:53.818, 6200612845785, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 999 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:42:54.827, 6200622935678, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1008 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:42:55.835, 6200633021067, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1008 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:42:56.849, 6200643158217, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1013 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:42:57.862, 6200653286764, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1012 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:42:58.876, 6200663422108, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1013 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:42:59.882, 6200673487785, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1006 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:43:00.883, 6200683492119, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1000 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:43:01.891, 6200693579085, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1008 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:43:02.906, 6200703726303, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1014 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:43:03.912, 6200713786348, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1005 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:43:04.924, 6200723910241, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1012 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:43:05.936, 6200734024691, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1011 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:43:06.937, 6200744041770, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1001 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:43:07.948, 6200754149533, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1010 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:43:08.955, 6200764216631, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1006 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:43:09.964, 6200774304509, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1008 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:43:10.971, 6200784376412, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1007 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:43:11.983, 6200794493660, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1011 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:43:12.992, 6200804590081, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1009 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:43:14.001, 6200814675014, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1008 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:43:15.007, 6200824737073, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1006 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:43:16.020, 6200834866083, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1012 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:43:17.021, 6200844880377, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1001 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:43:18.024, 6200854902563, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1002 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:43:19.032, 6200864988999, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1008 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:43:20.047, 6200875137767, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1014 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:43:21.060, 6200885264100, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1012 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:43:22.072, 6200895387625, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1012 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:43:23.076, 6200905426202, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1003 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:43:24.084, 6200915503997, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1007 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:43:25.098, 6200925642703, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1013 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:43:26.110, 6200935765046, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1012 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:43:27.122, 6200945884572, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1011 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:43:28.127, 6200955936620, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1005 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:43:29.141, 6200966073158, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1013 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:43:30.154, 6200976208984, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1013 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:43:31.169, 6200986355701, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1014 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:43:32.182, 6200996488147, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1013 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:43:33.186, 6201006523105, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1003 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:43:34.195, 6201016612198, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1008 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:43:35.204, 6201026702795, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1008 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:43:36.217, 6201036839906, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1013 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:43:37.223, 6201046896884, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1005 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:43:38.239, 6201057052975, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1015 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:43:39.252, 6201067188285, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1013 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:43:40.260, 6201077271874, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1008 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:43:41.270, 6201087366078, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1009 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:43:42.270, 6201097371895, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1000 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:43:43.272, 6201107382811, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1000 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:43:44.277, 6201117439274, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1005 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:43:45.284, 6201127511865, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1007 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:43:46.294, 6201137602393, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1008 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:43:47.294, 6201147607811, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1000 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:43:48.308, 6201157747021, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1013 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:43:49.324, 6201167902956, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1015 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:43:50.329, 6201177961064, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1005 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:43:51.338, 6201188047338, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1008 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:43:52.348, 6201198142988, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1009 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:43:53.353, 6201208193786, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1004 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:43:54.367, 6201218336559, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1014 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:43:55.368, 6201228350947, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1001 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:43:56.382, 6201238491489, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1013 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:43:57.394, 6201248603135, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1011 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:43:58.403, 6201258701097, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1009 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:43:59.413, 6201268792142, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1008 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:44:00.427, 6201278941902, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1014 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:44:01.435, 6201289018189, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1007 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:44:02.436, 6201299025382, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1000 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:44:03.441, 6201309075517, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1004 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:44:04.453, 6201319200723, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1012 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:44:05.454, 6201329206429, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1000 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:44:06.459, 6201339260378, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1005 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:44:07.463, 6201349294861, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1003 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:44:08.465, 6201359314147, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1001 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:44:09.475, 6201369421728, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1010 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:44:10.479, 6201379459267, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1003 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:44:11.485, 6201389519183, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1005 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:44:12.488, 6201399551365, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1003 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:44:13.503, 6201409697833, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1014 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:44:14.505, 6201419712456, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1001 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:44:15.512, 6201429782578, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1006 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:44:16.515, 6201439819666, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1003 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:44:17.530, 6201449964831, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1014 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:44:18.539, 6201460061322, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1009 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:44:19.554, 6201470206616, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1014 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:44:20.559, 6201480255474, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1004 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:44:21.559, 6201490260422, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1000 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:44:22.569, 6201500359178, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1009 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:44:23.584, 6201510508222, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1014 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:44:24.589, 6201520559817, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1005 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:44:25.595, 6201530617591, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1005 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:44:26.608, 6201540751691, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1013 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:44:27.614, 6201550802189, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1004 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:44:28.615, 6201560817710, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1001 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:44:29.615, 6201570821555, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1000 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:44:30.619, 6201580854861, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1003 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:44:31.629, 6201590956967, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1010 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:44:32.641, 6201601077080, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1011 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:44:33.648, 6201611146679, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1006 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:44:34.659, 6201621256699, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1010 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:44:35.662, 6201631287723, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1002 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:44:36.667, 6201641338681, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1004 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:44:37.670, 6201651368215, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1002 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:44:38.672, 6201661383919, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1001 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:44:39.679, 6201671455353, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1007 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:44:40.689, 6201681552734, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1009 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:44:41.699, 6201691653923, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1010 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:44:42.699, 6201701660308, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1000 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:44:43.705, 6201711714214, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1005 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:44:44.716, 6201721826765, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1011 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:44:45.719, 6201731860387, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1003 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:44:46.727, 6201741939537, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1007 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:44:47.735, 6201752013279, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1007 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:44:48.742, 6201762086049, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1007 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:44:49.747, 6201772141892, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1005 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:44:50.757, 6201782237892, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1009 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:44:51.766, 6201792327223, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1008 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:44:52.777, 6201802434016, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1010 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:44:53.791, 6201812579759, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1014 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:44:54.798, 6201822646318, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1006 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:44:55.800, 6201832669269, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1002 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:44:56.810, 6201842766049, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1009 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:44:57.817, 6201852840710, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1007 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:44:58.831, 6201862978949, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1013 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:44:59.840, 6201873065916, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1008 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:45:00.842, 6201883088079, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1002 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:45:01.847, 6201893132775, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1004 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:45:02.850, 6201903167756, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1003 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:45:03.860, 6201913265302, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1009 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:45:04.862, 6201923282873, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1001 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:45:05.870, 6201933364420, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1008 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:45:06.879, 6201943454013, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1008 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:45:07.892, 6201953586782, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1013 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:45:08.892, 6201963590329, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1000 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:45:09.901, 6201973674867, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1008 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:45:10.910, 6201983767176, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1009 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:45:11.922, 6201993884940, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1011 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:45:12.926, 6202003931529, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1004 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:45:13.932, 6202013991053, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1005 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:45:14.935, 6202024018950, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1002 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:45:15.936, 6202034029168, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1000 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:45:16.941, 6202044081944, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1005 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:45:17.954, 6202054203573, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1012 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:45:18.968, 6202064343451, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1013 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:45:19.976, 6202074424451, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1007 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:45:20.978, 6202084446198, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1002 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:45:21.978, 6202094449836, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1000 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:45:22.979, 6202104457486, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1000 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:45:23.983, 6202114495262, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1003 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:45:24.989, 6202124552301, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1005 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:45:25.998, 6202134643906, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1009 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:45:27.001, 6202144679844, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1003 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:45:28.002, 6202154686089, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1000 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:45:29.007, 6202164735896, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1004 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:45:30.014, 6202174804428, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1006 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:45:31.028, 6202184951274, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1014 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:45:32.043, 6202195099306, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1014 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:45:33.054, 6202205210244, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1010 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:45:34.069, 6202215355358, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1014 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:45:35.074, 6202225404929, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1004 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:45:36.079, 6202235460583, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1005 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:45:37.094, 6202245607267, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1014 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:45:38.099, 6202255654839, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1004 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:45:39.111, 6202265772180, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1011 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:45:40.122, 6202275886606, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1011 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:45:41.125, 6202285912236, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1002 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:45:42.128, 6202295950070, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1003 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:45:43.140, 6202306070462, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1011 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:45:44.154, 6202316210713, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1013 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:45:45.170, 6202326363443, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1015 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:45:46.183, 6202336499774, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1013 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:45:47.196, 6202346624883, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1012 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:45:48.199, 6202356659312, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1003 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:45:49.212, 6202366790643, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1013 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:45:50.226, 6202376923805, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1013 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:45:51.237, 6202387032015, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1010 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:45:52.249, 6202397153407, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1012 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:45:53.253, 6202407194464, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1003 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:45:54.260, 6202417264658, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1006 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:45:55.273, 6202427398341, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1013 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:45:56.275, 6202437417247, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1001 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:45:57.283, 6202447492627, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1007 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:45:58.287, 6202457536237, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1004 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:45:59.287, 6202467540707, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1000 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:46:00.288, 6202477548457, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1000 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:46:01.298, 6202487644299, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1009 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:46:02.312, 6202497785050, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1013 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:46:03.322, 6202507884300, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1009 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:46:04.332, 6202517989302, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1010 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:46:05.347, 6202528141808, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1015 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:46:06.354, 6202538210848, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1006 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:46:07.364, 6202548306615, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1009 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:46:08.375, 6202558418033, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1011 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:46:09.386, 6202568530895, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1011 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:46:10.393, 6202578600972, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1006 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:46:11.404, 6202588705131, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1010 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:46:12.416, 6202598826150, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1011 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:46:13.426, 6202608922878, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1009 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:46:14.433, 6202618996064, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1007 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:46:15.441, 6202629077434, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1008 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:46:16.452, 6202639188872, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1011 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:46:17.461, 6202649273762, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1008 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:46:18.469, 6202659356809, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1008 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:46:19.483, 6202669496052, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1013 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:46:20.497, 6202679640120, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1014 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:46:21.512, 6202689788090, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1014 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:46:22.526, 6202699924463, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1013 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:46:23.526, 6202709925384, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 999 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:46:24.526, 6202719926096, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 999 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:46:25.540, 6202730065353, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1013 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:46:26.551, 6202740175334, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1010 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:46:27.562, 6202750283630, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1010 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:46:28.567, 6202760336519, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1005 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:46:29.578, 6202770444033, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1010 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:46:30.582, 6202780489552, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1004 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:46:31.598, 6202790644732, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1015 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:46:32.602, 6202800684422, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1003 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:46:33.615, 6202810819881, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1013 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:46:34.625, 6202820917876, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1009 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:46:35.634, 6202831003283, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1008 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:46:36.647, 6202841141607, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1013 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:46:37.660, 6202851268399, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1012 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:46:38.663, 6202861299094, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1002 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:46:39.670, 6202871364221, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1006 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:46:40.673, 6202881396735, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1003 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:46:41.676, 6202891425430, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1002 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:46:42.687, 6202901536992, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1011 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:46:43.696, 6202911625821, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1008 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:46:44.702, 6202921691316, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1006 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:46:45.714, 6202931807814, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1011 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:46:46.725, 6202941920882, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1011 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:46:47.730, 6202951969991, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1004 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:46:48.745, 6202962113490, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1014 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:46:49.750, 6202972166134, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1005 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:46:50.760, 6202982265783, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1009 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:46:51.768, 6202992343149, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1007 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:46:52.777, 6203002437063, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1009 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:46:53.792, 6203012590865, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1015 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:46:54.801, 6203022677575, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1008 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:46:55.801, 6203032681014, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1000 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:46:56.817, 6203042833472, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1015 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:46:57.823, 6203052897744, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1006 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:46:58.828, 6203062950382, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1005 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:46:59.834, 6203073010355, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1005 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:47:00.841, 6203083073840, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1006 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:47:01.854, 6203093211807, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1013 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:47:02.868, 6203103344094, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1013 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:47:03.875, 6203113421692, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1007 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:47:04.888, 6203123545474, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1012 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:47:05.898, 6203133645963, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1009 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:47:06.901, 6203143679304, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1003 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:47:07.907, 6203153737802, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1005 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:47:08.919, 6203163860791, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1012 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:47:09.934, 6203174003361, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1014 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:47:10.945, 6203184119072, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1011 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:47:11.959, 6203194260099, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1013 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:47:12.963, 6203204298912, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1003 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:47:13.968, 6203214343879, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1004 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:47:14.982, 6203224487458, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1014 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:47:15.994, 6203234607240, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1011 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:47:17.007, 6203244740674, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1013 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:47:18.015, 6203254820523, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1007 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:47:19.024, 6203264904257, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1008 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:47:20.031, 6203274979643, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1007 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:47:21.039, 6203285056518, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1007 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:47:22.052, 6203295185436, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1012 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:47:23.062, 6203305285605, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1009 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:47:24.073, 6203315398680, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1011 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:47:25.080, 6203325467913, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1006 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:47:26.089, 6203335552034, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1008 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:47:27.093, 6203345596536, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1004 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:47:28.107, 6203355737671, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1014 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:47:29.122, 6203365887419, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1014 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:47:30.124, 6203375911847, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1002 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:47:31.133, 6203385999000, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1008 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:47:32.138, 6203396047786, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1004 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:47:33.148, 6203406143725, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1009 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:47:34.158, 6203416243647, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1009 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:47:35.170, 6203426364204, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1011 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:47:36.182, 6203436491047, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1012 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:47:37.186, 6203446526964, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1003 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:47:38.199, 6203456660593, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1013 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:47:39.214, 6203466806703, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1014 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:47:40.229, 6203476958470, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1015 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:47:41.238, 6203487050396, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1009 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:47:42.251, 6203497173869, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1012 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:47:43.253, 6203507198344, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1002 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:47:44.254, 6203517203789, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1000 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:47:45.259, 6203527253522, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1004 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:47:46.260, 6203537263468, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1000 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:47:47.266, 6203547326142, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1006 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:47:48.279, 6203557452294, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1012 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:47:49.285, 6203567515706, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1006 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:47:50.289, 6203577555450, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1003 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:47:51.290, 6203587565556, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1000 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:47:52.291, 6203597573668, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1000 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:47:53.301, 6203607681389, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1010 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:47:54.311, 6203617775939, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1009 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:47:55.313, 6203627794887, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1001 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:47:56.315, 6203637817512, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1002 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:47:57.323, 6203647899477, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1008 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:47:58.324, 6203657903681, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1000 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:47:58.795, 6203662615347, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: NotifyDataAvailable remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:47:58.795, 6203662620177, vstest.console.dll, TestRequestSender.OnExecutionMessageReceived: Received message: {"Version":7,"MessageType":"TestSession.Message","Payload":{"MessageLevel":0,"Message":"[testcontainers.org 00:00:00.06] Connected to Docker:\r\n Host: npipe://./pipe/docker_engine\r\n Server Version: 29.4.3\r\n Kernel Version: 6.12.76-linuxkit\r\n API Version: 1.54\r\n Operating System: Docker Desktop\r\n Total Memory: 3.82 GB\r\n Labels: \r\n com.docker.desktop.address=npipe://\\\\.\\pipe\\docker_cli\r\n[testcontainers.org 00:00:00.13] Docker network ab5c7ec2ca97 created\r\n[testcontainers.org 00:00:00.40] Docker container bb704f0c4c72 created\r\n[testcontainers.org 00:00:00.46] Start Docker container bb704f0c4c72\r\n[testcontainers.org 00:00:00.72] Wait for Docker container bb704f0c4c72 to complete readiness checks\r\n[testcontainers.org 00:00:01.79] Docker container bb704f0c4c72 ready\r\n[testcontainers.org 00:00:01.90] Docker container 80cc17022ab1 created\r\n[testcontainers.org 00:00:01.91] Start Docker container 80cc17022ab1\r\n[testcontainers.org 00:00:03.92] Wait for Docker container 80cc17022ab1 to complete readiness checks\r\n[testcontainers.org 00:00:03.93] Docker container 80cc17022ab1 ready\r\n[testcontainers.org 00:00:34.37] Docker container 1df1fd9fb44e created\r\n[testcontainers.org 00:00:34.38] Start Docker container 1df1fd9fb44e\r\n[testcontainers.org 00:00:34.58] Wait for Docker container 1df1fd9fb44e to complete readiness checks\r\n[testcontainers.org 00:00:34.59] Docker container 1df1fd9fb44e ready\r\n[testcontainers.org 00:01:34.74] Docker container 7752202c2996 created\r\n[testcontainers.org 00:01:34.75] Start Docker container 7752202c2996\r\n[testcontainers.org 00:01:34.99] Wait for Docker container 7752202c2996 to complete readiness checks\r\n[testcontainers.org 00:01:35.00] Docker container 7752202c2996 ready\r\nAbout to Start Security Container\r\n[testcontainers.org 00:03:55.58] Docker container e7bbcc0242ca created\r\n[testcontainers.org 00:03:55.59] Start Docker container e7bbcc0242ca\r\n[testcontainers.org 00:03:55.87] Wait for Docker container e7bbcc0242ca to complete readiness checks\r\n[testcontainers.org 00:03:55.87] Docker container e7bbcc0242ca ready\r\n[testcontainers.org 00:04:21.97] Docker container 0ead7ba827ae created\r\n[testcontainers.org 00:04:21.98] Start Docker container 0ead7ba827ae\r\n[testcontainers.org 00:04:22.32] Wait for Docker container 0ead7ba827ae to complete readiness checks\r\n[testcontainers.org 00:04:22.33] Docker container 0ead7ba827ae ready\r\n[testcontainers.org 00:04:43.73] Docker container 54b1d3f6190d created\r\n[testcontainers.org 00:04:43.77] Start Docker container 54b1d3f6190d\r\n[testcontainers.org 00:04:44.66] Wait for Docker container 54b1d3f6190d to complete readiness checks\r\n[testcontainers.org 00:04:44.70] Docker container 54b1d3f6190d ready\r\n[testcontainers.org 00:05:05.18] Docker container 7c75f5814a9d created\r\n[testcontainers.org 00:05:05.19] Start Docker container 7c75f5814a9d\r\n[testcontainers.org 00:05:05.45] Wait for Docker container 7c75f5814a9d to complete readiness checks\r\n[testcontainers.org 00:05:05.46] Docker container 7c75f5814a9d ready\r\n[testcontainers.org 00:05:26.34] Docker container 40d813ea0972 created\r\n[testcontainers.org 00:05:26.38] Start Docker container 40d813ea0972\r\n[testcontainers.org 00:05:26.96] Wait for Docker container 40d813ea0972 to complete readiness checks\r\n[testcontainers.org 00:05:26.97] Docker container 40d813ea0972 ready\r\n[testcontainers.org 00:05:47.61] Docker container 995f11910ea1 created\r\n[testcontainers.org 00:05:47.63] Start Docker container 995f11910ea1\r\n[testcontainers.org 00:05:48.00] Wait for Docker container 995f11910ea1 to complete readiness checks\r\n[testcontainers.org 00:05:48.01] Docker container 995f11910ea1 ready\r\n[testcontainers.org 00:06:08.50] Docker container 939f1947584d created\r\n[testcontainers.org 00:06:08.51] Start Docker container 939f1947584d\r\n[testcontainers.org 00:06:08.81] Wait for Docker container 939f1947584d to complete readiness checks\r\n[testcontainers.org 00:06:08.81] Docker container 939f1947584d ready\r\nGiven I create the following roles\r\n --- table step argument ---\r\n | Role Name |\r\n | Administrator |\r\n | Estate |\r\n-> done: BackgroundSteps.GivenICreateTheFollowingRoles(
) (0.7s)\r\nGiven I create the following api scopes\r\n --- table step argument ---\r\n | Name | DisplayName | Description |\r\n | transactionProcessor | Transaction Processor REST Scope | Scope for Transaction Processor REST |\r\n | fileProcessor | File Processor REST Scope | Scope for File Processor REST |\r\n-> done: BackgroundSteps.GivenICreateTheFollowingApiScopes(
) (0.2s)\r\nGiven I create the following api resources\r\n --- table step argument ---\r\n | Name | DisplayName | Secret | Scopes | UserClaims |\r\n | estateManagement | Estate Managememt REST | Secret1 | estateManagement | merchantId,estateId,role |\r\n | transactionProcessor | Transaction Processor REST | Secret1 | transactionProcessor | merchantId,estateId,role |\r\n | fileProcessor | File Processor REST | Secret1 | fileProcessor | merchantId,estateId,role |\r\n-> done: BackgroundSteps.GivenICreateTheFollowingApiResources(
) (0.2s)\r\nGiven I create the following identity resources\r\n --- table step argument ---\r\n | Name | DisplayName | Description | UserClaims |\r\n | openid | Your user identifier | | sub |\r\n | profile | User profile | Your user profile information (first name, last name, etc.) | name,role,email,given_name,middle_name,family_name,estateId,merchantId |\r\n | email | Email | Email and Email Verified Flags | email_verified,email |\r\n-> done: BackgroundSteps.GivenICreateTheFollowingIdentityResources(
) (0.2s)\r\nGiven I create the following clients\r\n --- table step argument ---\r\n | ClientId | Name | Secret | Scopes | GrantTypes | RedirectUris | PostLogoutRedirectUris | RequireConsent | AllowOfflineAccess | ClientUri |\r\n | serviceClient | Service Client | Secret1 | transactionProcessor | client_credentials | | | | | |\r\n | estateUIClient | Merchant Client | Secret1 | fileProcessor,transactionProcessor,openid,email,profile | hybrid | https://localhost:[port]/signin-oidc | https://localhost:[port]/signout-oidc | false | true | https://[url]:[port] |\r\n-> done: BackgroundSteps.GivenICreateTheFollowingClients(
) (0.2s)\r\nGiven I create the following users\r\n --- table step argument ---\r\n | Email Address | Phone Number | Given Name | Middle Name | Family Name | Claims | Roles |\r\n | administrator@admin.co.uk | 123456789 | Test | | User 1 | | Administrator |\r\n-> done: BackgroundSteps.GivenICreateTheFollowingUsers(
) (0.7s)\r\nGiven the user navigates to the app address\r\n-> done: DashboardSteps.GivenTheUserNavigatesToTheAppAddress() (1.3s)\r\nAnd I click on the Sign In Button\r\nSign in before click: https://localhost:65083/entry\r\nSign in after click: https://localhost:65083/login\r\n-> done: DashboardSteps.WhenIClickOnTheSignInButton() (2.1s)\r\nThen I am presented with a login screen\r\n-> error: (await IsAnyVisibleAsync(\r\n \"#Input_Username\",\r\n \"input[name='Input.Username']\",\r\n \"#Username\",\r\n \"input[name='Username']\",\r\n \"input[name='username']\",\r\n \"input[type='email']\"))\r\n should be\r\nTrue\r\n but was\r\nFalse (0.0s)\r\nWhen I login with the username 'administrator@admin.co.uk' and password '123456'\r\n-> skipped because of previous errors\r\nThen I should see the dashboard heading\r\n-> skipped because of previous errors\r\nAnd I should see the administrator welcome panel\r\n-> skipped because of previous errors\r\nAnd I should not see the merchant KPI summary cards\r\n-> skipped because of previous errors\r\nAnd I should not see the sales comparison cards\r\n-> skipped because of previous errors\r\nAnd I should not see the recent merchants section\r\n-> skipped because of previous errors\r\nScreenshot saved to: screenshot-Administrators_see_the_dashboard_welcome_panel-20260619134749.png\r\n[testcontainers.org 00:06:16.87] Stop Docker container 939f1947584d\r\n[testcontainers.org 00:06:17.21] Delete Docker container 939f1947584d\r\n[testcontainers.org 00:06:17.27] Stop Docker container 995f11910ea1\r\n[testcontainers.org 00:06:17.71] Delete Docker container 995f11910ea1\r\n[testcontainers.org 00:06:17.74] Stop Docker container 40d813ea0972\r\n[testcontainers.org 00:06:18.14] Delete Docker container 40d813ea0972\r\n[testcontainers.org 00:06:18.18] Stop Docker container 7c75f5814a9d\r\n[testcontainers.org 00:06:18.60] Delete Docker container 7c75f5814a9d\r\n[testcontainers.org 00:06:18.64] Stop Docker container 54b1d3f6190d\r\n[testcontainers.org 00:06:20.52] Delete Docker container 54b1d3f6190d\r\n[testcontainers.org 00:06:20.68] Stop Docker container 0ead7ba827ae\r\n[testcontainers.org 00:06:21.30] Delete Docker container 0ead7ba827ae\r\n[testcontainers.org 00:06:21.34] Stop Docker container e7bbcc0242ca\r\n[testcontainers.org 00:06:21.81] Delete Docker container e7bbcc0242ca\r\n[testcontainers.org 00:06:21.86] Stop Docker container 7752202c2996\r\n[testcontainers.org 00:06:22.33] Delete Docker container 7752202c2996\r\n[testcontainers.org 00:06:22.41] Stop Docker container 1df1fd9fb44e\r\n[testcontainers.org 00:06:23.65] Delete Docker container 1df1fd9fb44e\r\n[testcontainers.org 00:06:23.89] Stop Docker container 80cc17022ab1\r\n[testcontainers.org 00:06:25.86] Delete Docker container 80cc17022ab1\r\n[testcontainers.org 00:06:25.93] Delete Docker network ab5c7ec2ca97\r\n"}} +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:47:58.796, 6203662624261, vstest.console.dll, TestRunRequest:SendTestRunMessage: Starting. +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:47:58.796, 6203662625065, vstest.console.dll, MulticastDelegateUtilities.SafeInvoke: TestRun.LogMessages: Invoking callback 1/1 for Microsoft.VisualStudio.TestPlatform.CommandLine.TestRunResultAggregator., took 0 ms. +TpTrace Information: 0 : 48056, 10, 2026/06/19, 13:47:58.796, 6203662625381, vstest.console.dll, TestRunRequest:SendTestRunMessage: Completed. +TpTrace Verbose: 0 : 48056, 4, 2026/06/19, 13:47:58.796, 6203662625636, vstest.console.dll, MulticastDelegateUtilities.SafeInvoke: InternalTestLoggerEvents.SendTestRunMessage: Invoking callback 1/1 for Microsoft.VisualStudio.TestPlatform.CommandLine.Internal.ConsoleLogger., took 0 ms. +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:47:58.796, 6203662625659, vstest.console.dll, MulticastDelegateUtilities.SafeInvoke: LengthPrefixCommunicationChannel: MessageReceived: Invoking callback 1/1 for Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.TestRequestSender+<>c__DisplayClass34_0., took 0 ms. +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:47:58.796, 6203662626688, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 472 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:47:59.166, 6203666324149, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: NotifyDataAvailable remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:47:59.166, 6203666328883, vstest.console.dll, TestRequestSender.OnExecutionMessageReceived: Received message: {"Version":7,"MessageType":"TestExecution.StatsChange","Payload":{"NewTestResults":[{"TestCase":{"Id":"856509a0-37bf-5299-e232-e80e305d4dd4","FullyQualifiedName":"EstateManagementUI.IntegrationTests.Features.DashboardFeature.AdministratorsSeeTheDashboardWelcomePanel","DisplayName":"AdministratorsSeeTheDashboardWelcomePanel","ExecutorUri":"executor://NUnit3TestExecutor","Source":"D:\\Projects\\TransactionProcessing\\EstateManagementUI\\EstateManagementUI.IntegrationTests\\bin\\Debug\\net10.0\\EstateManagementUI.IntegrationTests.dll","CodeFilePath":null,"LineNumber":0,"Properties":[{"Key":{"Id":"NUnit.TestCategory","Label":"TestCategory","Category":"","Description":"","Attributes":5,"ValueType":"System.String[]"},"Value":["base","background","dashboard","Dashboard","AdministratorRole"]},{"Key":{"Id":"NUnit.Seed","Label":"Seed","Category":"","Description":"","Attributes":0,"ValueType":"System.String"},"Value":"1743199602"}]},"Attachments":[],"Outcome":2,"ErrorMessage":"Shouldly.ShouldAssertException : (await IsAnyVisibleAsync(\r\n \"#Input_Username\",\r\n \"input[name='Input.Username']\",\r\n \"#Username\",\r\n \"input[name='Username']\",\r\n \"input[name='username']\",\r\n \"input[type='email']\"))\r\n should be\r\nTrue\r\n but was\r\nFalse","ErrorStackTrace":" at EstateManagementUI.IntegrationTests.Common.DashboardPageHelper.AssertLoginScreenVisibleAsync() in D:\\Projects\\TransactionProcessing\\EstateManagementUI\\EstateManagementUI.IntegrationTests\\Common\\DashboardPageHelper.cs:line 42\r\n at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task, ConfigureAwaitOptions options)\r\n at EstateManagementUI.IntegrationTests.Steps.DashboardSteps.ThenIAmPresentedWithALoginScreen() in D:\\Projects\\TransactionProcessing\\EstateManagementUI\\EstateManagementUI.IntegrationTests\\Steps\\DashboardSteps.cs:line 35\r\n at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task, ConfigureAwaitOptions options)\r\n at Reqnroll.Bindings.AsyncMethodHelper.ConvertTaskOfT(Task task, Boolean getValue)\r\n at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task, ConfigureAwaitOptions options)\r\n at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()\r\n at Reqnroll.Bindings.BindingDelegateInvoker.InvokeDelegateAsync(Delegate bindingDelegate, Object[] invokeArgs, ExecutionContextHolder executionContext)\r\n at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task, ConfigureAwaitOptions options)\r\n at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()\r\n at Reqnroll.Bindings.BindingInvoker.InvokeBindingAsync(IBinding binding, IContextManager contextManager, Object[] arguments, ITestTracer testTracer, DurationHolder durationHolder)\r\n at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task, ConfigureAwaitOptions options)\r\n at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()\r\n at Reqnroll.Infrastructure.TestExecutionEngine.ExecuteStepMatchAsync(BindingMatch match, Object[] arguments, DurationHolder durationHolder)\r\n at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n at Reqnroll.Infrastructure.TestExecutionEngine.ExecuteStepMatchAsync(BindingMatch match, Object[] arguments, DurationHolder durationHolder)\r\n at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task, ConfigureAwaitOptions options)\r\n at Reqnroll.Infrastructure.TestExecutionEngine.<>c__DisplayClass57_0.<b__7>d.MoveNext()\r\n--- End of stack trace from previous location ---\r\n at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task, ConfigureAwaitOptions options)\r\n at Reqnroll.Infrastructure.TestExecutionEngine.<>c__DisplayClass57_0.<g__HandleStepExecutionExceptions|0>d.MoveNext()\n1) at EstateManagementUI.IntegrationTests.Common.DashboardPageHelper.AssertLoginScreenVisibleAsync() in D:\\Projects\\TransactionProcessing\\EstateManagementUI\\EstateManagementUI.IntegrationTests\\Common\\DashboardPageHelper.cs:line 42\r\n at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task, ConfigureAwaitOptions options)\r\n at EstateManagementUI.IntegrationTests.Steps.DashboardSteps.ThenIAmPresentedWithALoginScreen() in D:\\Projects\\TransactionProcessing\\EstateManagementUI\\EstateManagementUI.IntegrationTests\\Steps\\DashboardSteps.cs:line 35\r\n at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task, ConfigureAwaitOptions options)\r\n at Reqnroll.Bindings.AsyncMethodHelper.ConvertTaskOfT(Task task, Boolean getValue)\r\n at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task, ConfigureAwaitOptions options)\r\n at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()\r\n at Reqnroll.Bindings.BindingDelegateInvoker.InvokeDelegateAsync(Delegate bindingDelegate, Object[] invokeArgs, ExecutionContextHolder executionContext)\r\n at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task, ConfigureAwaitOptions options)\r\n at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()\r\n at Reqnroll.Bindings.BindingInvoker.InvokeBindingAsync(IBinding binding, IContextManager contextManager, Object[] arguments, ITestTracer testTracer, DurationHolder durationHolder)\r\n at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task, ConfigureAwaitOptions options)\r\n at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()\r\n at Reqnroll.Infrastructure.TestExecutionEngine.ExecuteStepMatchAsync(BindingMatch match, Object[] arguments, DurationHolder durationHolder)\r\n at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n at Reqnroll.Infrastructure.TestExecutionEngine.ExecuteStepMatchAsync(BindingMatch match, Object[] arguments, DurationHolder durationHolder)\r\n at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task, ConfigureAwaitOptions options)\r\n at Reqnroll.Infrastructure.TestExecutionEngine.<>c__DisplayClass57_0.<b__7>d.MoveNext()\r\n--- End of stack trace from previous location ---\r\n at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task, ConfigureAwaitOptions options)\r\n at Reqnroll.Infrastructure.TestExecutionEngine.<>c__DisplayClass57_0.<g__HandleStepExecutionExceptions|0>d.MoveNext()\n","DisplayName":"AdministratorsSeeTheDashboardWelcomePanel","Messages":[{"Category":"StdOutMsgs","Text":"[testcontainers.org 00:00:00.06] Connected to Docker:\r\n Host: npipe://./pipe/docker_engine\r\n Server Version: 29.4.3\r\n Kernel Version: 6.12.76-linuxkit\r\n API Version: 1.54\r\n Operating System: Docker Desktop\r\n Total Memory: 3.82 GB\r\n Labels: \r\n com.docker.desktop.address=npipe://\\\\.\\pipe\\docker_cli\r\n[testcontainers.org 00:00:00.13] Docker network ab5c7ec2ca97 created\r\n[testcontainers.org 00:00:00.40] Docker container bb704f0c4c72 created\r\n[testcontainers.org 00:00:00.46] Start Docker container bb704f0c4c72\r\n[testcontainers.org 00:00:00.72] Wait for Docker container bb704f0c4c72 to complete readiness checks\r\n[testcontainers.org 00:00:01.79] Docker container bb704f0c4c72 ready\r\n[testcontainers.org 00:00:01.90] Docker container 80cc17022ab1 created\r\n[testcontainers.org 00:00:01.91] Start Docker container 80cc17022ab1\r\n[testcontainers.org 00:00:03.92] Wait for Docker container 80cc17022ab1 to complete readiness checks\r\n[testcontainers.org 00:00:03.93] Docker container 80cc17022ab1 ready\r\n[testcontainers.org 00:00:34.37] Docker container 1df1fd9fb44e created\r\n[testcontainers.org 00:00:34.38] Start Docker container 1df1fd9fb44e\r\n[testcontainers.org 00:00:34.58] Wait for Docker container 1df1fd9fb44e to complete readiness checks\r\n[testcontainers.org 00:00:34.59] Docker container 1df1fd9fb44e ready\r\n[testcontainers.org 00:01:34.74] Docker container 7752202c2996 created\r\n[testcontainers.org 00:01:34.75] Start Docker container 7752202c2996\r\n[testcontainers.org 00:01:34.99] Wait for Docker container 7752202c2996 to complete readiness checks\r\n[testcontainers.org 00:01:35.00] Docker container 7752202c2996 ready\r\nAbout to Start Security Container\r\n[testcontainers.org 00:03:55.58] Docker container e7bbcc0242ca created\r\n[testcontainers.org 00:03:55.59] Start Docker container e7bbcc0242ca\r\n[testcontainers.org 00:03:55.87] Wait for Docker container e7bbcc0242ca to complete readiness checks\r\n[testcontainers.org 00:03:55.87] Docker container e7bbcc0242ca ready\r\n[testcontainers.org 00:04:21.97] Docker container 0ead7ba827ae created\r\n[testcontainers.org 00:04:21.98] Start Docker container 0ead7ba827ae\r\n[testcontainers.org 00:04:22.32] Wait for Docker container 0ead7ba827ae to complete readiness checks\r\n[testcontainers.org 00:04:22.33] Docker container 0ead7ba827ae ready\r\n[testcontainers.org 00:04:43.73] Docker container 54b1d3f6190d created\r\n[testcontainers.org 00:04:43.77] Start Docker container 54b1d3f6190d\r\n[testcontainers.org 00:04:44.66] Wait for Docker container 54b1d3f6190d to complete readiness checks\r\n[testcontainers.org 00:04:44.70] Docker container 54b1d3f6190d ready\r\n[testcontainers.org 00:05:05.18] Docker container 7c75f5814a9d created\r\n[testcontainers.org 00:05:05.19] Start Docker container 7c75f5814a9d\r\n[testcontainers.org 00:05:05.45] Wait for Docker container 7c75f5814a9d to complete readiness checks\r\n[testcontainers.org 00:05:05.46] Docker container 7c75f5814a9d ready\r\n[testcontainers.org 00:05:26.34] Docker container 40d813ea0972 created\r\n[testcontainers.org 00:05:26.38] Start Docker container 40d813ea0972\r\n[testcontainers.org 00:05:26.96] Wait for Docker container 40d813ea0972 to complete readiness checks\r\n[testcontainers.org 00:05:26.97] Docker container 40d813ea0972 ready\r\n[testcontainers.org 00:05:47.61] Docker container 995f11910ea1 created\r\n[testcontainers.org 00:05:47.63] Start Docker container 995f11910ea1\r\n[testcontainers.org 00:05:48.00] Wait for Docker container 995f11910ea1 to complete readiness checks\r\n[testcontainers.org 00:05:48.01] Docker container 995f11910ea1 ready\r\n[testcontainers.org 00:06:08.50] Docker container 939f1947584d created\r\n[testcontainers.org 00:06:08.51] Start Docker container 939f1947584d\r\n[testcontainers.org 00:06:08.81] Wait for Docker container 939f1947584d to complete readiness checks\r\n[testcontainers.org 00:06:08.81] Docker container 939f1947584d ready\r\nGiven I create the following roles\r\n --- table step argument ---\r\n | Role Name |\r\n | Administrator |\r\n | Estate |\r\n-> done: BackgroundSteps.GivenICreateTheFollowingRoles(
) (0.7s)\r\nGiven I create the following api scopes\r\n --- table step argument ---\r\n | Name | DisplayName | Description |\r\n | transactionProcessor | Transaction Processor REST Scope | Scope for Transaction Processor REST |\r\n | fileProcessor | File Processor REST Scope | Scope for File Processor REST |\r\n-> done: BackgroundSteps.GivenICreateTheFollowingApiScopes(
) (0.2s)\r\nGiven I create the following api resources\r\n --- table step argument ---\r\n | Name | DisplayName | Secret | Scopes | UserClaims |\r\n | estateManagement | Estate Managememt REST | Secret1 | estateManagement | merchantId,estateId,role |\r\n | transactionProcessor | Transaction Processor REST | Secret1 | transactionProcessor | merchantId,estateId,role |\r\n | fileProcessor | File Processor REST | Secret1 | fileProcessor | merchantId,estateId,role |\r\n-> done: BackgroundSteps.GivenICreateTheFollowingApiResources(
) (0.2s)\r\nGiven I create the following identity resources\r\n --- table step argument ---\r\n | Name | DisplayName | Description | UserClaims |\r\n | openid | Your user identifier | | sub |\r\n | profile | User profile | Your user profile information (first name, last name, etc.) | name,role,email,given_name,middle_name,family_name,estateId,merchantId |\r\n | email | Email | Email and Email Verified Flags | email_verified,email |\r\n-> done: BackgroundSteps.GivenICreateTheFollowingIdentityResources(
) (0.2s)\r\nGiven I create the following clients\r\n --- table step argument ---\r\n | ClientId | Name | Secret | Scopes | GrantTypes | RedirectUris | PostLogoutRedirectUris | RequireConsent | AllowOfflineAccess | ClientUri |\r\n | serviceClient | Service Client | Secret1 | transactionProcessor | client_credentials | | | | | |\r\n | estateUIClient | Merchant Client | Secret1 | fileProcessor,transactionProcessor,openid,email,profile | hybrid | https://localhost:[port]/signin-oidc | https://localhost:[port]/signout-oidc | false | true | https://[url]:[port] |\r\n-> done: BackgroundSteps.GivenICreateTheFollowingClients(
) (0.2s)\r\nGiven I create the following users\r\n --- table step argument ---\r\n | Email Address | Phone Number | Given Name | Middle Name | Family Name | Claims | Roles |\r\n | administrator@admin.co.uk | 123456789 | Test | | User 1 | | Administrator |\r\n-> done: BackgroundSteps.GivenICreateTheFollowingUsers(
) (0.7s)\r\nGiven the user navigates to the app address\r\n-> done: DashboardSteps.GivenTheUserNavigatesToTheAppAddress() (1.3s)\r\nAnd I click on the Sign In Button\r\nSign in before click: https://localhost:65083/entry\r\nSign in after click: https://localhost:65083/login\r\n-> done: DashboardSteps.WhenIClickOnTheSignInButton() (2.1s)\r\nThen I am presented with a login screen\r\n-> error: (await IsAnyVisibleAsync(\r\n \"#Input_Username\",\r\n \"input[name='Input.Username']\",\r\n \"#Username\",\r\n \"input[name='Username']\",\r\n \"input[name='username']\",\r\n \"input[type='email']\"))\r\n should be\r\nTrue\r\n but was\r\nFalse (0.0s)\r\nWhen I login with the username 'administrator@admin.co.uk' and password '123456'\r\n-> skipped because of previous errors\r\nThen I should see the dashboard heading\r\n-> skipped because of previous errors\r\nAnd I should see the administrator welcome panel\r\n-> skipped because of previous errors\r\nAnd I should not see the merchant KPI summary cards\r\n-> skipped because of previous errors\r\nAnd I should not see the sales comparison cards\r\n-> skipped because of previous errors\r\nAnd I should not see the recent merchants section\r\n-> skipped because of previous errors\r\nScreenshot saved to: screenshot-Administrators_see_the_dashboard_welcome_panel-20260619134749.png\r\n[testcontainers.org 00:06:16.87] Stop Docker container 939f1947584d\r\n[testcontainers.org 00:06:17.21] Delete Docker container 939f1947584d\r\n[testcontainers.org 00:06:17.27] Stop Docker container 995f11910ea1\r\n[testcontainers.org 00:06:17.71] Delete Docker container 995f11910ea1\r\n[testcontainers.org 00:06:17.74] Stop Docker container 40d813ea0972\r\n[testcontainers.org 00:06:18.14] Delete Docker container 40d813ea0972\r\n[testcontainers.org 00:06:18.18] Stop Docker container 7c75f5814a9d\r\n[testcontainers.org 00:06:18.60] Delete Docker container 7c75f5814a9d\r\n[testcontainers.org 00:06:18.64] Stop Docker container 54b1d3f6190d\r\n[testcontainers.org 00:06:20.52] Delete Docker container 54b1d3f6190d\r\n[testcontainers.org 00:06:20.68] Stop Docker container 0ead7ba827ae\r\n[testcontainers.org 00:06:21.30] Delete Docker container 0ead7ba827ae\r\n[testcontainers.org 00:06:21.34] Stop Docker container e7bbcc0242ca\r\n[testcontainers.org 00:06:21.81] Delete Docker container e7bbcc0242ca\r\n[testcontainers.org 00:06:21.86] Stop Docker container 7752202c2996\r\n[testcontainers.org 00:06:22.33] Delete Docker container 7752202c2996\r\n[testcontainers.org 00:06:22.41] Stop Docker container 1df1fd9fb44e\r\n[testcontainers.org 00:06:23.65] Delete Docker container 1df1fd9fb44e\r\n[testcontainers.org 00:06:23.89] Stop Docker container 80cc17022ab1\r\n[testcontainers.org 00:06:25.86] Delete Docker container 80cc17022ab1\r\n[testcontainers.org 00:06:25.93] Delete Docker network ab5c7ec2ca97\r\n"}],"ComputerName":"DESKTOP-FJ3HD6D","Duration":"00:06:26.6414899","StartTime":"2026-06-19T12:41:32.1201917+00:00","EndTime":"2026-06-19T12:47:58.7615187+00:00","Properties":[{"Key":{"Id":"NUnit.Seed","Label":"Seed","Category":"","Description":"","Attributes":0,"ValueType":"System.String"},"Value":"1743199602"}]}],"TestRunStatistics":{"ExecutedTests":1,"Stats":{"Failed":1}},"ActiveTests":[]}} +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:47:59.178, 6203666443472, vstest.console.dll, TestRunRequest:SendTestRunStatsChange: Starting. +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:47:59.178, 6203666446742, vstest.console.dll, MulticastDelegateUtilities.SafeInvoke: TestRun.RunStatsChanged: Invoking callbacks was skipped because there are no subscribers. +TpTrace Information: 0 : 48056, 10, 2026/06/19, 13:47:59.178, 6203666447208, vstest.console.dll, TestRunRequest:SendTestRunStatsChange: Completed. +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:47:59.178, 6203666447664, vstest.console.dll, MulticastDelegateUtilities.SafeInvoke: LengthPrefixCommunicationChannel: MessageReceived: Invoking callback 1/1 for Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.TestRequestSender+<>c__DisplayClass34_0., took 11 ms. +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:47:59.178, 6203666448199, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 382 ms +TpTrace Verbose: 0 : 48056, 4, 2026/06/19, 13:47:59.183, 6203666499969, vstest.console.dll, MulticastDelegateUtilities.SafeInvoke: InternalTestLoggerEvents.SendTestResult: Invoking callback 1/1 for Microsoft.VisualStudio.TestPlatform.CommandLine.Internal.ConsoleLogger., took 5 ms. +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:48:00.193, 6203676595674, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: Polling on remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 after 1014 ms +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:48:00.335, 6203678021644, vstest.console.dll, TcpClientExtensions.MessageLoopAsync: NotifyDataAvailable remoteEndPoint: 127.0.0.1:62256 localEndPoint: 127.0.0.1:62255 +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:48:00.336, 6203678026082, vstest.console.dll, TestRequestSender.OnExecutionMessageReceived: Received message: {"Version":7,"MessageType":"TestExecution.Completed","Payload":{"TestRunCompleteArgs":{"TestRunStatistics":{"ExecutedTests":1,"Stats":{"Failed":1}},"IsCanceled":false,"IsAborted":false,"Error":null,"AttachmentSets":[],"InvokedDataCollectors":[],"ElapsedTimeInRunningTests":"00:06:29.7681925","Metrics":{},"DiscoveredExtensions":{"TestDiscoverers":["NUnit.VisualStudio.TestAdapter.NUnit3TestDiscoverer, NUnit3.TestAdapter, Version=1.0.0.0, Culture=neutral, PublicKeyToken=4cb40d35494691ac"],"TestExecutors":["executor://NUnit3TestExecutor"],"TestExecutors2":[],"TestSettingsProviders":[]}},"LastRunTests":{"NewTestResults":[],"TestRunStatistics":{"ExecutedTests":1,"Stats":{"Failed":1}},"ActiveTests":[]},"RunAttachments":[],"ExecutorUris":["executor://nunit3testexecutor/"]}} +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:48:00.336, 6203678027270, vstest.console.dll, TestRequestSender.EndSession: Sending end session. +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:48:00.336, 6203678029147, vstest.console.dll, ProxyOperationManager.Close: waiting for test host to exit for 100 ms +TpTrace Warning: 0 : 48056, 11, 2026/06/19, 13:48:00.379, 6203678458508, vstest.console.dll, TestHostManagerCallbacks.ErrorReceivedCallback Test host standard error line: +TpTrace Verbose: 0 : 48056, 12, 2026/06/19, 13:48:00.379, 6203678458477, vstest.console.dll, TestHostManagerCallbacks.StandardOutputReceivedCallback Test host standard output line: +TpTrace Warning: 0 : 48056, 10, 2026/06/19, 13:48:00.437, 6203679042148, vstest.console.dll, ProxyOperationManager: Timed out waiting for test host to exit. Will terminate process. +TpTrace Information: 0 : 48056, 10, 2026/06/19, 13:48:00.438, 6203679044236, vstest.console.dll, SocketServer.Stop: Stop server endPoint: 127.0.0.1:62255 +TpTrace Information: 0 : 48056, 10, 2026/06/19, 13:48:00.438, 6203679044874, vstest.console.dll, SocketServer.Stop: Cancellation requested. Stopping message loop. +TpTrace Information: 0 : 48056, 10, 2026/06/19, 13:48:00.438, 6203679048493, vstest.console.dll, Closing the connection +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:48:00.441, 6203679081672, vstest.console.dll, TestHostProvider.ExitCallBack: Host exited starting callback. +TpTrace Information: 0 : 48056, 10, 2026/06/19, 13:48:00.442, 6203679082668, vstest.console.dll, TestHostManagerCallbacks.ExitCallBack: Testhost processId: 53008 exited with exitcode: 0 error: '' +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:48:00.442, 6203679083097, vstest.console.dll, DotnetTestHostManager.OnHostExited: invoking OnHostExited callback +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:48:00.442, 6203679086974, vstest.console.dll, CrossPlatEngine.TestHostManagerHostExited: calling on client process exit callback. +TpTrace Information: 0 : 48056, 10, 2026/06/19, 13:48:00.442, 6203679087659, vstest.console.dll, TestRequestSender.OnClientProcessExit: Test host process exited. Standard error: +TpTrace Information: 0 : 48056, 10, 2026/06/19, 13:48:00.442, 6203679088369, vstest.console.dll, SocketServer.Stop: Stop server endPoint: 127.0.0.1:62255 +TpTrace Information: 0 : 48056, 10, 2026/06/19, 13:48:00.442, 6203679088715, vstest.console.dll, SocketServer.Stop: Cancellation requested. Stopping message loop. +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:48:00.442, 6203679089034, vstest.console.dll, MulticastDelegateUtilities.SafeInvoke: HostProviderEvents.OnHostExited: Invoking callback 1/1 for Microsoft.VisualStudio.TestPlatform.CrossPlatEngine.Client.ProxyOperationManager., took 0 ms. +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:48:00.459, 6203679258108, vstest.console.dll, ParallelRunEventsHandler.HandleTestRunComplete: Handling a run completion, this can be either one part of parallel run completing, or the whole parallel run completing. +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:48:00.465, 6203679313580, vstest.console.dll, TestRunRequest:SendTestRunStatsChange: Starting. +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:48:00.465, 6203679314932, vstest.console.dll, MulticastDelegateUtilities.SafeInvoke: TestRun.RunStatsChanged: Invoking callbacks was skipped because there are no subscribers. +TpTrace Information: 0 : 48056, 10, 2026/06/19, 13:48:00.465, 6203679315362, vstest.console.dll, TestRunRequest:SendTestRunStatsChange: Completed. +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:48:00.466, 6203679326128, vstest.console.dll, ParallelProxyExecutionManager: HandlePartialRunComplete: Total workloads = 1, Total started clients = 1 Total completed clients = 1, Run complete = True, Run canceled: False. +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:48:00.466, 6203679326869, vstest.console.dll, ParallelProxyExecutionManager: HandlePartialRunComplete: All runs completed stopping all managers. +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:48:00.466, 6203679327254, vstest.console.dll, ParallelOperationManager.StopAllManagers: Stopping all managers. +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:48:00.466, 6203679327596, vstest.console.dll, ParallelOperationManager.ClearSlots: Clearing all slots. Slots should accept more work: False +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:48:00.466, 6203679328792, vstest.console.dll, ParallelOperationManager.SetOccupiedSlotCount: Setting slot counts AvailableSlotCount = 1, OccupiedSlotCount = 0. +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:48:00.466, 6203679330091, vstest.console.dll, Occupied slots: + +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:48:00.466, 6203679330464, vstest.console.dll, ParallelRunEventsHandler.HandleTestRunComplete: Whole parallel run completed. +TpTrace Verbose: 0 : 48056, 4, 2026/06/19, 13:48:00.485, 6203679519421, vstest.console.dll, MulticastDelegateUtilities.SafeInvoke: InternalTestLoggerEvents.SendTestRunComplete: Invoking callback 1/1 for Microsoft.VisualStudio.TestPlatform.CommandLine.Internal.ConsoleLogger., took 7 ms. +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:48:00.486, 6203679526033, vstest.console.dll, TestRunRequest:TestRunComplete: Starting. IsAborted:False IsCanceled:False. +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:48:00.486, 6203679527962, vstest.console.dll, ParallelOperationManager.DoActionOnAllManagers: Calling an action on all managers. +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:48:00.489, 6203679555884, vstest.console.dll, TestLoggerManager.HandleTestRunComplete: Ignoring as the object is disposed. +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:48:00.490, 6203679570244, vstest.console.dll, MulticastDelegateUtilities.SafeInvoke: TestRun.TestRunComplete: Invoking callback 1/2 for Microsoft.VisualStudio.TestPlatform.CommandLine.TestRunResultAggregator., took 1 ms. +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:48:00.490, 6203679571768, vstest.console.dll, MulticastDelegateUtilities.SafeInvoke: TestRun.TestRunComplete: Invoking callback 2/2 for Microsoft.VisualStudio.TestPlatform.CommandLine.Processors.RunTestsArgumentExecutor+TestRunRequestEventsRegistrar., took 0 ms. +TpTrace Verbose: 0 : 48056, 2, 2026/06/19, 13:48:00.491, 6203679574808, vstest.console.dll, TestRunRequest.Dispose: Starting. +TpTrace Information: 0 : 48056, 10, 2026/06/19, 13:48:00.491, 6203679576137, vstest.console.dll, TestRunRequest:TestRunComplete: Completed. +TpTrace Information: 0 : 48056, 2, 2026/06/19, 13:48:00.491, 6203679577424, vstest.console.dll, TestRunRequest.Dispose: Completed. +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:48:00.491, 6203679577362, vstest.console.dll, TestRequestSender.SetOperationComplete: Setting operation complete. +TpTrace Information: 0 : 48056, 2, 2026/06/19, 13:48:00.491, 6203679578041, vstest.console.dll, TestRequestManager.RunTests: run tests completed. +TpTrace Information: 0 : 48056, 10, 2026/06/19, 13:48:00.491, 6203679578369, vstest.console.dll, SocketServer.Stop: Stop server endPoint: 127.0.0.1:62255 +TpTrace Information: 0 : 48056, 10, 2026/06/19, 13:48:00.491, 6203679579961, vstest.console.dll, SocketServer.Stop: Cancellation requested. Stopping message loop. +TpTrace Information: 0 : 48056, 2, 2026/06/19, 13:48:00.491, 6203679580149, vstest.console.dll, RunTestsArgumentProcessor:Execute: Test run is completed. +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:48:00.491, 6203679580271, vstest.console.dll, MulticastDelegateUtilities.SafeInvoke: LengthPrefixCommunicationChannel: MessageReceived: Invoking callback 1/1 for Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.TestRequestSender+<>c__DisplayClass34_0., took 155 ms. +TpTrace Information: 0 : 48056, 10, 2026/06/19, 13:48:00.491, 6203679581374, vstest.console.dll, SocketServer.PrivateStop: Stopping server endPoint: 127.0.0.1:62255 error: +TpTrace Verbose: 0 : 48056, 2, 2026/06/19, 13:48:00.492, 6203679582566, vstest.console.dll, Executor.Execute: Exiting with exit code of 1 +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:48:00.492, 6203679590929, vstest.console.dll, LengthPrefixCommunicationChannel.Dispose: Dispose reader and writer. +TpTrace Information: 0 : 48056, 10, 2026/06/19, 13:48:00.492, 6203679591696, vstest.console.dll, SocketServer.Stop: Raise disconnected event endPoint: 127.0.0.1:62255 error: +TpTrace Verbose: 0 : 48056, 10, 2026/06/19, 13:48:00.493, 6203679592811, vstest.console.dll, TestRequestSender: OnTestRunAbort: Operation is already complete. Skip error message. From 8e4570341629ab6d2525229050ad47c6a3090b90 Mon Sep 17 00:00:00 2001 From: StuartFerguson Date: Sun, 21 Jun 2026 08:56:20 +0100 Subject: [PATCH 02/17] Refactor pull request workflow to include chrometests --- .github/workflows/pullrequest.yml | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/.github/workflows/pullrequest.yml b/.github/workflows/pullrequest.yml index 29f36e39..9f869fa0 100644 --- a/.github/workflows/pullrequest.yml +++ b/.github/workflows/pullrequest.yml @@ -48,9 +48,8 @@ jobs: name: test-results path: '**/TestResults/*.trx' retention-days: 30 - - - chrometests: + + chrometests: name: "Build and Test UI - Chrome" env: ASPNETCORE_ENVIRONMENT: "Production" @@ -210,4 +209,4 @@ jobs: # if: ${{ failure() }} # with: # name: firefoxtracelogs -# path: /home/txnproc/trace/ \ No newline at end of file +# path: /home/txnproc/trace/ From 1cbc8c68fcce7aa4a4e32ee738c1c575c9ade7a6 Mon Sep 17 00:00:00 2001 From: StuartFerguson Date: Sun, 21 Jun 2026 09:30:47 +0100 Subject: [PATCH 03/17] Update pullrequest.yml --- .github/workflows/pullrequest.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pullrequest.yml b/.github/workflows/pullrequest.yml index 9f869fa0..5088ff0d 100644 --- a/.github/workflows/pullrequest.yml +++ b/.github/workflows/pullrequest.yml @@ -86,7 +86,7 @@ jobs: sudo chmod 400 /etc/ssl/private/aspnetapp-root-cert.key - name: Build Docker Image - run: docker build . --file EstateManagementUI/Dockerfile --tag estatemanagementui:latest + run: docker build . --file EstateManagementUI.BlazorServer/Dockerfile --tag estatemanagementui:latest - name: Restore Nuget Packages run: dotnet restore EstateManagementUI.sln --source ${{ secrets.PUBLICFEEDURL }} --source ${{ secrets.PRIVATEFEED_URL }} From 0c3b08dffc4a64eb7be39235466c1acedb8ae8f2 Mon Sep 17 00:00:00 2001 From: StuartFerguson Date: Sun, 21 Jun 2026 09:54:39 +0100 Subject: [PATCH 04/17] Update Docker image tag in pullrequest.yml --- .github/workflows/pullrequest.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pullrequest.yml b/.github/workflows/pullrequest.yml index 5088ff0d..08c5083f 100644 --- a/.github/workflows/pullrequest.yml +++ b/.github/workflows/pullrequest.yml @@ -86,7 +86,7 @@ jobs: sudo chmod 400 /etc/ssl/private/aspnetapp-root-cert.key - name: Build Docker Image - run: docker build . --file EstateManagementUI.BlazorServer/Dockerfile --tag estatemanagementui:latest + run: docker build . --file EstateManagementUI.BlazorServer/Dockerfile --tag estatemanagementuiblazorserver:latest - name: Restore Nuget Packages run: dotnet restore EstateManagementUI.sln --source ${{ secrets.PUBLICFEEDURL }} --source ${{ secrets.PRIVATEFEED_URL }} From cddd804e67fd2271108ae879416a46a5a56a77bb Mon Sep 17 00:00:00 2001 From: StuartFerguson Date: Sun, 21 Jun 2026 14:20:44 +0100 Subject: [PATCH 05/17] Upload Playwright screenshots on test failure Updated GitHub Actions workflow to upload Playwright screenshots as artifacts when integration tests fail. Modified BrowserHooks to save screenshots in a dedicated TestResults/Screenshots directory for better organization and artifact collection. --- .github/workflows/pullrequest.yml | 9 ++++++++- .../Hooks/BrowserHooks.cs | 5 ++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/.github/workflows/pullrequest.yml b/.github/workflows/pullrequest.yml index 29f36e39..bddc7959 100644 --- a/.github/workflows/pullrequest.yml +++ b/.github/workflows/pullrequest.yml @@ -97,6 +97,13 @@ jobs: Browser: Chrome IsCI: true run: dotnet test "EstateManagementUI.IntegrationTests\EstateManagementUI.IntegrationTests.csproj" # --filter Category=PRTest + + - name: Upload Playwright screenshots on failure + uses: actions/upload-artifact@v4.4.0 + if: ${{ failure() }} + with: + name: chrometestresults + path: EstateManagementUI.IntegrationTests/TestResults/ - uses: actions/upload-artifact@v4.4.0 if: ${{ failure() }} @@ -210,4 +217,4 @@ jobs: # if: ${{ failure() }} # with: # name: firefoxtracelogs -# path: /home/txnproc/trace/ \ No newline at end of file +# path: /home/txnproc/trace/ diff --git a/EstateManagementUI.IntegrationTests/Hooks/BrowserHooks.cs b/EstateManagementUI.IntegrationTests/Hooks/BrowserHooks.cs index bcc41d1b..fbce8b04 100644 --- a/EstateManagementUI.IntegrationTests/Hooks/BrowserHooks.cs +++ b/EstateManagementUI.IntegrationTests/Hooks/BrowserHooks.cs @@ -2,6 +2,7 @@ using Reqnroll; using System.Net; using System.Net.Sockets; +using System.IO; namespace EstateManagementUI.IntegrationTests.Hooks; @@ -65,7 +66,9 @@ public async Task AfterScenario() if (_scenarioContext.TestError != null) { var scenarioName = _scenarioContext.ScenarioInfo.Title.Replace(" ", "_"); - var screenshotPath = $"screenshot-{scenarioName}-{DateTime.Now:yyyyMMddHHmmss}.png"; + var screenshotDirectory = Path.Combine(Environment.CurrentDirectory, "TestResults", "Screenshots"); + Directory.CreateDirectory(screenshotDirectory); + var screenshotPath = Path.Combine(screenshotDirectory, $"screenshot-{scenarioName}-{DateTime.Now:yyyyMMddHHmmss}.png"); await page.ScreenshotAsync(new PageScreenshotOptions { Path = screenshotPath, From 269a2e353edc903d46b7a38e74afbd2897a04852 Mon Sep 17 00:00:00 2001 From: StuartFerguson Date: Sun, 21 Jun 2026 14:41:21 +0100 Subject: [PATCH 06/17] Update Playwright artifact path in CI workflow Changed the Playwright screenshot upload step in pullrequest.yml to use a generic '**/TestResults/**' path. This ensures test results from any TestResults directory are included in the uploaded artifacts, improving coverage and reliability of test result collection. --- .github/workflows/pullrequest.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pullrequest.yml b/.github/workflows/pullrequest.yml index 1dfddcf4..7044754e 100644 --- a/.github/workflows/pullrequest.yml +++ b/.github/workflows/pullrequest.yml @@ -102,7 +102,7 @@ jobs: if: ${{ failure() }} with: name: chrometestresults - path: EstateManagementUI.IntegrationTests/TestResults/ + path: '**/TestResults/**' - uses: actions/upload-artifact@v4.4.0 if: ${{ failure() }} From 7779f5b23674e150643d0cb98139c6fe150d598b Mon Sep 17 00:00:00 2001 From: StuartFerguson Date: Sun, 21 Jun 2026 15:12:05 +0100 Subject: [PATCH 07/17] more debug for failure --- .../Common/DashboardPageHelper.cs | 309 ++++++++++++------ .../Hooks/BrowserHooks.cs | 36 +- 2 files changed, 249 insertions(+), 96 deletions(-) diff --git a/EstateManagementUI.IntegrationTests/Common/DashboardPageHelper.cs b/EstateManagementUI.IntegrationTests/Common/DashboardPageHelper.cs index 23d54b16..40790e81 100644 --- a/EstateManagementUI.IntegrationTests/Common/DashboardPageHelper.cs +++ b/EstateManagementUI.IntegrationTests/Common/DashboardPageHelper.cs @@ -3,6 +3,8 @@ using Shouldly; using System.Text.Json; using System.Text.RegularExpressions; +using System.IO; +using System.Text; using Shared.IntegrationTesting; namespace EstateManagementUI.IntegrationTests.Common; @@ -19,130 +21,160 @@ public DashboardPageHelper(IPage page, TestingContext testingContext) { public async Task NavigateToAppAddressAsync() { - var baseUrl = ResolveBaseUrl(); - await _page.GotoAsync(baseUrl); - await _page.WaitForLoadStateAsync(LoadState.NetworkIdle); + await RunWithFailureArtifactsAsync(async () => + { + var baseUrl = ResolveBaseUrl(); + await _page.GotoAsync(baseUrl); + await _page.WaitForLoadStateAsync(LoadState.NetworkIdle); + }, nameof(NavigateToAppAddressAsync)); } public async Task ClickSignInButtonAsync() { - var signInButton = _page.Locator("#loginButton"); + await RunWithFailureArtifactsAsync(async () => + { + var signInButton = _page.Locator("#loginButton"); - (await signInButton.IsVisibleAsync()).ShouldBeTrue(); - Console.WriteLine($"Sign in before click: {_page.Url}"); + (await signInButton.IsVisibleAsync()).ShouldBeTrue(); + Console.WriteLine($"Sign in before click: {_page.Url}"); - await signInButton.ClickAsync(); - await _page.WaitForTimeoutAsync(2000); - Console.WriteLine($"Sign in after click: {_page.Url}"); - Console.WriteLine($"Sign in title after click: {await _page.TitleAsync()}"); - Console.WriteLine($"Sign in body after click: {await _page.Locator("body").InnerTextAsync()}"); + await signInButton.ClickAsync(); + await _page.WaitForTimeoutAsync(2000); + Console.WriteLine($"Sign in after click: {_page.Url}"); + Console.WriteLine($"Sign in title after click: {await _page.TitleAsync()}"); + Console.WriteLine($"Sign in body after click: {await _page.Locator("body").InnerTextAsync()}"); + }, nameof(ClickSignInButtonAsync)); } public async Task AssertLoginScreenVisibleAsync() { - await _page.WaitForLoadStateAsync(LoadState.DOMContentLoaded); - - (await WaitForAnyVisibleAsync( - "#Input_Username", - "input[name='Input.Username']", - "#Username", - "input[name='Username']", - "input[name='username']", - "input[type='email']", - "input[type='text']", - "input[autocomplete='username']")).ShouldBeTrue(); - - (await WaitForAnyVisibleAsync( - "#Input_Password", - "input[name='Input.Password']", - "#Password", - "input[name='Password']", - "input[name='password']", - "input[type='password']", - "input[autocomplete='current-password']")).ShouldBeTrue(); + await RunWithFailureArtifactsAsync(async () => + { + await _page.WaitForLoadStateAsync(LoadState.DOMContentLoaded); + + (await WaitForAnyVisibleAsync( + "#Input_Username", + "input[name='Input.Username']", + "#Username", + "input[name='Username']", + "input[name='username']", + "input[type='email']", + "input[type='text']", + "input[autocomplete='username']")).ShouldBeTrue(); + + (await WaitForAnyVisibleAsync( + "#Input_Password", + "input[name='Input.Password']", + "#Password", + "input[name='Password']", + "input[name='password']", + "input[type='password']", + "input[autocomplete='current-password']")).ShouldBeTrue(); + }, nameof(AssertLoginScreenVisibleAsync)); } public async Task LoginAsync(string username, string password) { - await FillFirstVisibleAsync( - username, - "#Input_Username", - "input[name='Input.Username']", - "#Username", - "input[name='Username']", - "input[name='username']", - "input[type='email']", - "input[type='text']", - "input[autocomplete='username']"); - - await FillFirstVisibleAsync( - password, - "#Input_Password", - "input[name='Input.Password']", - "#Password", - "input[name='Password']", - "input[name='password']", - "input[type='password']", - "input[autocomplete='current-password']"); - - await ClickFirstVisibleAsync( - "button[type='submit']", - "input[type='submit']", - "button:has-text('Sign In')", - "button:has-text('Login')"); - - await _page.WaitForLoadStateAsync(LoadState.NetworkIdle); + await RunWithFailureArtifactsAsync(async () => + { + await FillFirstVisibleAsync( + username, + "#Input_Username", + "input[name='Input.Username']", + "#Username", + "input[name='Username']", + "input[name='username']", + "input[type='email']", + "input[type='text']", + "input[autocomplete='username']"); + + await FillFirstVisibleAsync( + password, + "#Input_Password", + "input[name='Input.Password']", + "#Password", + "input[name='Password']", + "input[name='password']", + "input[type='password']", + "input[autocomplete='current-password']"); + + await ClickFirstVisibleAsync( + "button[type='submit']", + "input[type='submit']", + "button:has-text('Sign In')", + "button:has-text('Login')"); + + await _page.WaitForLoadStateAsync(LoadState.NetworkIdle); + }, nameof(LoginAsync)); } public async Task AssertDashboardShellVisibleAsync() { - (await _page.GetByRole(AriaRole.Heading, new() { Name = "Dashboard" }).IsVisibleAsync()).ShouldBeTrue(); - (await _page.GetByText("Welcome to Estate Management System").IsVisibleAsync()).ShouldBeTrue(); - (await _page.Locator("#dashboardLink").IsVisibleAsync()).ShouldBeTrue(); + await RunWithFailureArtifactsAsync(async () => + { + (await _page.GetByRole(AriaRole.Heading, new() { Name = "Dashboard" }).IsVisibleAsync()).ShouldBeTrue(); + (await _page.GetByText("Welcome to Estate Management System").IsVisibleAsync()).ShouldBeTrue(); + (await _page.Locator("#dashboardLink").IsVisibleAsync()).ShouldBeTrue(); + }, nameof(AssertDashboardShellVisibleAsync)); } public async Task AssertHomePageVisibleAsync() { - (await _page.TitleAsync()).ShouldBe("Welcome - Estate Management"); - (await _page.Locator("#loginButton").IsVisibleAsync()).ShouldBeTrue(); + await RunWithFailureArtifactsAsync(async () => + { + (await _page.TitleAsync()).ShouldBe("Welcome - Estate Management"); + (await _page.Locator("#loginButton").IsVisibleAsync()).ShouldBeTrue(); + }, nameof(AssertHomePageVisibleAsync)); } public async Task AssertDashboardWelcomeMessageVisibleAsync() { - (await _page.GetByText("Welcome to Estate Management System").IsVisibleAsync()).ShouldBeTrue(); + await RunWithFailureArtifactsAsync(async () => + { + (await _page.GetByText("Welcome to Estate Management System").IsVisibleAsync()).ShouldBeTrue(); + }, nameof(AssertDashboardWelcomeMessageVisibleAsync)); } public async Task AssertEstateDashboardVisibleAsync() { - await AssertDashboardShellVisibleAsync(); - await AssertComparisonDateSelectorVisibleAsync(); - await AssertMerchantKpiSummaryCardsVisibleAsync(); - await AssertSalesComparisonCardsVisibleAsync(); - await AssertRecentMerchantsSectionVisibleAsync(); + await RunWithFailureArtifactsAsync(async () => + { + await AssertDashboardShellVisibleAsync(); + await AssertComparisonDateSelectorVisibleAsync(); + await AssertMerchantKpiSummaryCardsVisibleAsync(); + await AssertSalesComparisonCardsVisibleAsync(); + await AssertRecentMerchantsSectionVisibleAsync(); + }, nameof(AssertEstateDashboardVisibleAsync)); } public async Task AssertAdministratorDashboardVisibleAsync() { - await AssertDashboardShellVisibleAsync(); - (await _page.GetByRole(AriaRole.Heading, new() { Name = "Welcome, Administrator" }).IsVisibleAsync()).ShouldBeTrue(); + await RunWithFailureArtifactsAsync(async () => + { + await AssertDashboardShellVisibleAsync(); + (await _page.GetByRole(AriaRole.Heading, new() { Name = "Welcome, Administrator" }).IsVisibleAsync()).ShouldBeTrue(); + }, nameof(AssertAdministratorDashboardVisibleAsync)); } public async Task AssertComparisonDateSelectorVisibleAsync() { - var selector = _page.Locator("#comparisonDateSelector"); - var deadline = DateTime.UtcNow.AddSeconds(10); - - while (DateTime.UtcNow < deadline) + await RunWithFailureArtifactsAsync(async () => { - if (await selector.IsVisibleAsync()) + var selector = _page.Locator("#comparisonDateSelector"); + var deadline = DateTime.UtcNow.AddSeconds(10); + + while (DateTime.UtcNow < deadline) { - return; - } + if (await selector.IsVisibleAsync()) + { + return; + } - await _page.WaitForTimeoutAsync(250); - } + await _page.WaitForTimeoutAsync(250); + } - (await _page.Locator("#comparisonDateSelector").IsVisibleAsync()).ShouldBeTrue(); + (await _page.Locator("#comparisonDateSelector").IsVisibleAsync()).ShouldBeTrue(); + }, nameof(AssertComparisonDateSelectorVisibleAsync)); } public async Task AssertMerchantKpiSummaryCardsVisibleAsync() @@ -150,45 +182,66 @@ public async Task AssertMerchantKpiSummaryCardsVisibleAsync() //await AssertInfoBoxVisibleAsync("Merchants with Sales (Last Hour)", "45"); //await AssertInfoBoxVisibleAsync("Merchants with No Sales Today", "12"); //await AssertInfoBoxVisibleAsync("Merchants with No Sales (7 Days)", "5"); - await AssertInfoBoxVisibleAsync("Merchants with Sales (Last Hour)", "0"); - await AssertInfoBoxVisibleAsync("Merchants with No Sales Today", "0"); - await AssertInfoBoxVisibleAsync("Merchants with No Sales (7 Days)", "0"); + await RunWithFailureArtifactsAsync(async () => + { + await AssertInfoBoxVisibleAsync("Merchants with Sales (Last Hour)", "0"); + await AssertInfoBoxVisibleAsync("Merchants with No Sales Today", "0"); + await AssertInfoBoxVisibleAsync("Merchants with No Sales (7 Days)", "0"); + }, nameof(AssertMerchantKpiSummaryCardsVisibleAsync)); } public async Task AssertSalesComparisonCardsVisibleAsync() { //await AssertCardVisibleAsync("Today's Sales", "523 transactions", new Regex(@"[£$]145,000\.00")); //await AssertCardVisibleAsync("Failed Sales (Low Credit)", "15 transactions", new Regex(@"[£$]850\.00")); - await AssertCardVisibleAsync("Today's Sales", "0 transactions", new Regex(@"[£$¤]\s?0(?:,000)?\.00")); - await AssertCardVisibleAsync("Failed Sales (Low Credit)", "0 transactions", new Regex(@"[£$¤]\s?0(?:,000)?\.00")); + await RunWithFailureArtifactsAsync(async () => + { + await AssertCardVisibleAsync("Today's Sales", "0 transactions", new Regex(@"[£$¤]\s?0(?:,000)?\.00")); + await AssertCardVisibleAsync("Failed Sales (Low Credit)", "0 transactions", new Regex(@"[£$¤]\s?0(?:,000)?\.00")); + }, nameof(AssertSalesComparisonCardsVisibleAsync)); } public async Task AssertRecentMerchantsSectionVisibleAsync() { - (await _page.GetByRole(AriaRole.Heading, new() { Name = "Recently Created Merchants" }).IsVisibleAsync()).ShouldBeTrue(); + await RunWithFailureArtifactsAsync(async () => + { + (await _page.GetByRole(AriaRole.Heading, new() { Name = "Recently Created Merchants" }).IsVisibleAsync()).ShouldBeTrue(); + }, nameof(AssertRecentMerchantsSectionVisibleAsync)); } public async Task AssertMerchantKpiSummaryCardsNotVisibleAsync() { - await AssertInfoBoxAbsentAsync("Merchants with Sales (Last Hour)"); - await AssertInfoBoxAbsentAsync("Merchants with No Sales Today"); - await AssertInfoBoxAbsentAsync("Merchants with No Sales (7 Days)"); + await RunWithFailureArtifactsAsync(async () => + { + await AssertInfoBoxAbsentAsync("Merchants with Sales (Last Hour)"); + await AssertInfoBoxAbsentAsync("Merchants with No Sales Today"); + await AssertInfoBoxAbsentAsync("Merchants with No Sales (7 Days)"); + }, nameof(AssertMerchantKpiSummaryCardsNotVisibleAsync)); } public async Task AssertSalesComparisonCardsNotVisibleAsync() { - await AssertCardAbsentAsync("Today's Sales"); - await AssertCardAbsentAsync("Failed Sales (Low Credit)"); + await RunWithFailureArtifactsAsync(async () => + { + await AssertCardAbsentAsync("Today's Sales"); + await AssertCardAbsentAsync("Failed Sales (Low Credit)"); + }, nameof(AssertSalesComparisonCardsNotVisibleAsync)); } public async Task AssertRecentMerchantsSectionNotVisibleAsync() { - (await _page.GetByRole(AriaRole.Heading, new() { Name = "Recently Created Merchants" }).CountAsync()).ShouldBe(0); + await RunWithFailureArtifactsAsync(async () => + { + (await _page.GetByRole(AriaRole.Heading, new() { Name = "Recently Created Merchants" }).CountAsync()).ShouldBe(0); + }, nameof(AssertRecentMerchantsSectionNotVisibleAsync)); } public async Task AssertDashboardNavigationLinkVisibleAsync() { - (await _page.Locator("#dashboardLink").IsVisibleAsync()).ShouldBeTrue(); + await RunWithFailureArtifactsAsync(async () => + { + (await _page.Locator("#dashboardLink").IsVisibleAsync()).ShouldBeTrue(); + }, nameof(AssertDashboardNavigationLinkVisibleAsync)); } private async Task AssertInfoBoxVisibleAsync(string label, string expectedValue) @@ -306,4 +359,70 @@ private string ResolveBaseUrl() var hostPort = this.TestingContext.DockerHelper.GetHostPort(ContainerType.EstateManagementUI); return $"https://localhost:{hostPort}"; } + + private async Task RunWithFailureArtifactsAsync(Func action, string context) + { + try + { + await action(); + } + catch (Exception ex) + { + await CaptureDebugArtifactsAsync(context, ex); + throw; + } + } + + private async Task CaptureDebugArtifactsAsync(string context, Exception exception) + { + try + { + var outputDirectory = Path.Combine(Environment.CurrentDirectory, "TestResults", "Diagnostics"); + Directory.CreateDirectory(outputDirectory); + + var timestamp = DateTime.Now.ToString("yyyyMMddHHmmss"); + var safeContext = context.Replace(" ", "_"); + var artifactPath = Path.Combine(outputDirectory, $"failure-{safeContext}-{timestamp}.txt"); + + var bodyText = string.Empty; + try + { + bodyText = await _page.Locator("body").InnerTextAsync(); + } + catch + { + bodyText = ""; + } + + var html = string.Empty; + try + { + html = await _page.ContentAsync(); + } + catch + { + html = ""; + } + + var content = new StringBuilder(); + content.AppendLine($"Context: {context}"); + content.AppendLine($"Exception: {exception.GetType().FullName}"); + content.AppendLine($"Message: {exception.Message}"); + content.AppendLine($"Url: {_page.Url}"); + content.AppendLine($"Title: {await _page.TitleAsync()}"); + content.AppendLine(); + content.AppendLine("Body:"); + content.AppendLine(bodyText); + content.AppendLine(); + content.AppendLine("Html:"); + content.AppendLine(html); + + await File.WriteAllTextAsync(artifactPath, content.ToString()); + Console.WriteLine($"Failure diagnostics saved to: {artifactPath}"); + } + catch (Exception captureException) + { + Console.WriteLine($"Failed to capture debug artifacts: {captureException.Message}"); + } + } } diff --git a/EstateManagementUI.IntegrationTests/Hooks/BrowserHooks.cs b/EstateManagementUI.IntegrationTests/Hooks/BrowserHooks.cs index fbce8b04..c7ae97a1 100644 --- a/EstateManagementUI.IntegrationTests/Hooks/BrowserHooks.cs +++ b/EstateManagementUI.IntegrationTests/Hooks/BrowserHooks.cs @@ -3,6 +3,7 @@ using System.Net; using System.Net.Sockets; using System.IO; +using System.Text; namespace EstateManagementUI.IntegrationTests.Hooks; @@ -58,7 +59,15 @@ public async Task BeforeScenario() [AfterScenario(Order = 0)] public async Task AfterScenario() { - var page = _scenarioContext.ScenarioContainer.Resolve(); + IPage? page = null; + try + { + page = _scenarioContext.ScenarioContainer.Resolve(); + } + catch + { + return; + } if (page != null) { @@ -67,7 +76,20 @@ public async Task AfterScenario() { var scenarioName = _scenarioContext.ScenarioInfo.Title.Replace(" ", "_"); var screenshotDirectory = Path.Combine(Environment.CurrentDirectory, "TestResults", "Screenshots"); + var diagnosticsDirectory = Path.Combine(Environment.CurrentDirectory, "TestResults", "Diagnostics"); Directory.CreateDirectory(screenshotDirectory); + Directory.CreateDirectory(diagnosticsDirectory); + + try + { + await page.WaitForLoadStateAsync(LoadState.DOMContentLoaded); + await page.WaitForTimeoutAsync(500); + } + catch + { + // Best effort only. If the page is already gone, we still want the failure artifacts. + } + var screenshotPath = Path.Combine(screenshotDirectory, $"screenshot-{scenarioName}-{DateTime.Now:yyyyMMddHHmmss}.png"); await page.ScreenshotAsync(new PageScreenshotOptions { @@ -75,6 +97,18 @@ await page.ScreenshotAsync(new PageScreenshotOptions FullPage = true }); Console.WriteLine($"Screenshot saved to: {screenshotPath}"); + + var diagnosticsPath = Path.Combine(diagnosticsDirectory, $"diagnostics-{scenarioName}-{DateTime.Now:yyyyMMddHHmmss}.txt"); + var diagnostics = new StringBuilder(); + diagnostics.AppendLine($"Url: {page.Url}"); + diagnostics.AppendLine($"Title: {await page.TitleAsync()}"); + diagnostics.AppendLine("Body text:"); + diagnostics.AppendLine(await page.Locator("body").InnerTextAsync()); + diagnostics.AppendLine(); + diagnostics.AppendLine("HTML:"); + diagnostics.AppendLine(await page.ContentAsync()); + await File.WriteAllTextAsync(diagnosticsPath, diagnostics.ToString()); + Console.WriteLine($"Diagnostics saved to: {diagnosticsPath}"); } await page.CloseAsync(); From b0c761e11e5709dc1528443b285abfc3f9cf174e Mon Sep 17 00:00:00 2001 From: StuartFerguson Date: Sun, 21 Jun 2026 15:35:27 +0100 Subject: [PATCH 08/17] .. --- .../Hooks/BrowserHooks.cs | 52 ++++++++++++++++--- 1 file changed, 44 insertions(+), 8 deletions(-) diff --git a/EstateManagementUI.IntegrationTests/Hooks/BrowserHooks.cs b/EstateManagementUI.IntegrationTests/Hooks/BrowserHooks.cs index c7ae97a1..b84a74e8 100644 --- a/EstateManagementUI.IntegrationTests/Hooks/BrowserHooks.cs +++ b/EstateManagementUI.IntegrationTests/Hooks/BrowserHooks.cs @@ -15,6 +15,7 @@ public class BrowserHooks { private static IPlaywright? _playwright; private static IBrowser? _browser; + private static IBrowserContext? _browserContext; private static TcpListener? _securityServiceForwarder; private static CancellationTokenSource? _forwarderCancellation; private readonly ScenarioContext _scenarioContext; @@ -68,18 +69,35 @@ public async Task AfterScenario() { return; } + + var scenarioName = _scenarioContext.ScenarioInfo.Title.Replace(" ", "_"); + var artifactDirectory = Path.Combine(Environment.CurrentDirectory, "TestResults"); + var screenshotDirectory = Path.Combine(artifactDirectory, "Screenshots"); + var diagnosticsDirectory = Path.Combine(artifactDirectory, "Diagnostics"); + var traceDirectory = Path.Combine(artifactDirectory, "Traces"); + Directory.CreateDirectory(screenshotDirectory); + Directory.CreateDirectory(diagnosticsDirectory); + Directory.CreateDirectory(traceDirectory); + + if (_browserContext != null) + { + try + { + var tracePath = Path.Combine(traceDirectory, $"trace-{scenarioName}-{DateTime.Now:yyyyMMddHHmmss}.zip"); + await _browserContext.Tracing.StopAsync(new TracingStopOptions { Path = tracePath }); + Console.WriteLine($"Trace saved to: {tracePath}"); + } + catch (Exception traceException) + { + Console.WriteLine($"Failed to save trace: {traceException.Message}"); + } + } if (page != null) { // Take screenshot on failure if (_scenarioContext.TestError != null) { - var scenarioName = _scenarioContext.ScenarioInfo.Title.Replace(" ", "_"); - var screenshotDirectory = Path.Combine(Environment.CurrentDirectory, "TestResults", "Screenshots"); - var diagnosticsDirectory = Path.Combine(Environment.CurrentDirectory, "TestResults", "Diagnostics"); - Directory.CreateDirectory(screenshotDirectory); - Directory.CreateDirectory(diagnosticsDirectory); - try { await page.WaitForLoadStateAsync(LoadState.DOMContentLoaded); @@ -113,6 +131,12 @@ await page.ScreenshotAsync(new PageScreenshotOptions await page.CloseAsync(); } + + if (_browserContext != null) + { + await _browserContext.CloseAsync(); + _browserContext = null; + } } /// @@ -201,13 +225,25 @@ private async Task CreateBrowserPage() }; } - var context = await _browser.NewContextAsync(new BrowserNewContextOptions + _browserContext = await _browser.NewContextAsync(new BrowserNewContextOptions { IgnoreHTTPSErrors = true, ViewportSize = new ViewportSize { Width = 1920, Height = 1080 } }); - return await context.NewPageAsync(); + await _browserContext.Tracing.StartAsync(new TracingStartOptions + { + Screenshots = true, + Snapshots = true, + Sources = true + }); + + var page = await _browserContext.NewPageAsync(); + page.Console += (_, message) => Console.WriteLine($"[browser console] {message.Type}: {message.Text}"); + page.PageError += (_, error) => Console.WriteLine($"[browser page error] {error}"); + page.RequestFailed += (_, request) => Console.WriteLine($"[browser request failed] {request.Url} => {request.Failure}"); + + return page; } private static async Task EnsureSecurityServiceForwarderAsync(int localPort, int targetPort) From 3a92405d28bb949076ea5c398a14650fa952abc5 Mon Sep 17 00:00:00 2001 From: StuartFerguson Date: Sun, 21 Jun 2026 15:39:42 +0100 Subject: [PATCH 09/17] Potential fix for pull request finding 'CodeQL / Workflow does not contain permissions' Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com> --- .github/workflows/pullrequest.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/pullrequest.yml b/.github/workflows/pullrequest.yml index 7044754e..78b65df6 100644 --- a/.github/workflows/pullrequest.yml +++ b/.github/workflows/pullrequest.yml @@ -5,6 +5,10 @@ on: branches: - main +permissions: + contents: read + checks: write + jobs: unittests: name: "Build and Unit Test" From 5550c9b805b1ecb378acd3298ce1d83a4605e76f Mon Sep 17 00:00:00 2001 From: StuartFerguson Date: Sun, 21 Jun 2026 19:56:20 +0100 Subject: [PATCH 10/17] .. --- .../Hooks/BrowserHooks.cs | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/EstateManagementUI.IntegrationTests/Hooks/BrowserHooks.cs b/EstateManagementUI.IntegrationTests/Hooks/BrowserHooks.cs index b84a74e8..c4fa8e98 100644 --- a/EstateManagementUI.IntegrationTests/Hooks/BrowserHooks.cs +++ b/EstateManagementUI.IntegrationTests/Hooks/BrowserHooks.cs @@ -4,6 +4,7 @@ using System.Net.Sockets; using System.IO; using System.Text; +using System.Text.RegularExpressions; namespace EstateManagementUI.IntegrationTests.Hooks; @@ -175,6 +176,11 @@ private async Task CreateBrowserPage() ? null : $"MAP {securityServiceHost} 127.0.0.1"; + Console.WriteLine($"[browser setup] Browser={browserType}, IsCI={isCI}"); + Console.WriteLine($"[browser setup] SecurityServiceContainerName={securityServiceHost ?? ""}"); + Console.WriteLine($"[browser setup] SecurityServiceLocalPort={securityServiceLocalPortText ?? ""}"); + Console.WriteLine($"[browser setup] SecurityServicePort={securityServicePortText ?? ""}"); + if (int.TryParse(securityServiceLocalPortText, out var localPort) && int.TryParse(securityServicePortText, out var targetPort) && localPort != targetPort) @@ -231,6 +237,30 @@ private async Task CreateBrowserPage() ViewportSize = new ViewportSize { Width = 1920, Height = 1080 } }); + if (!string.IsNullOrWhiteSpace(securityServiceHost) && + int.TryParse(securityServicePortText, out var securityServicePort)) + { + var securityServiceRoutePattern = new Regex( + $"^https://{Regex.Escape(securityServiceHost)}:\\d+/", + RegexOptions.IgnoreCase | RegexOptions.Compiled); + + await _browserContext.RouteAsync(securityServiceRoutePattern, async route => + { + var requestUri = new Uri(route.Request.Url); + var rewrittenUri = new UriBuilder(requestUri) + { + Host = "127.0.0.1", + Port = securityServicePort + }; + + Console.WriteLine($"[browser route rewrite] {route.Request.Url} => {rewrittenUri.Uri}"); + await route.ContinueAsync(new RouteContinueOptions + { + Url = rewrittenUri.Uri.ToString() + }); + }); + } + await _browserContext.Tracing.StartAsync(new TracingStartOptions { Screenshots = true, From 357fdb74887c47e7a8818b40d70c0bb3ed763a31 Mon Sep 17 00:00:00 2001 From: StuartFerguson Date: Sun, 21 Jun 2026 21:27:07 +0100 Subject: [PATCH 11/17] ... --- .../Hooks/BrowserHooks.cs | 74 ++++++++++++------- 1 file changed, 49 insertions(+), 25 deletions(-) diff --git a/EstateManagementUI.IntegrationTests/Hooks/BrowserHooks.cs b/EstateManagementUI.IntegrationTests/Hooks/BrowserHooks.cs index c4fa8e98..2f24c1db 100644 --- a/EstateManagementUI.IntegrationTests/Hooks/BrowserHooks.cs +++ b/EstateManagementUI.IntegrationTests/Hooks/BrowserHooks.cs @@ -1,10 +1,10 @@ using Microsoft.Playwright; using Reqnroll; using System.Net; +using System.Net.Http; using System.Net.Sockets; using System.IO; using System.Text; -using System.Text.RegularExpressions; namespace EstateManagementUI.IntegrationTests.Hooks; @@ -187,6 +187,8 @@ private async Task CreateBrowserPage() { await EnsureSecurityServiceForwarderAsync(localPort, targetPort); } + + await ProbeSecurityServiceConnectivityAsync(securityServiceHost, securityServiceLocalPortText, securityServicePortText); if (_browser == null) { @@ -237,30 +239,6 @@ private async Task CreateBrowserPage() ViewportSize = new ViewportSize { Width = 1920, Height = 1080 } }); - if (!string.IsNullOrWhiteSpace(securityServiceHost) && - int.TryParse(securityServicePortText, out var securityServicePort)) - { - var securityServiceRoutePattern = new Regex( - $"^https://{Regex.Escape(securityServiceHost)}:\\d+/", - RegexOptions.IgnoreCase | RegexOptions.Compiled); - - await _browserContext.RouteAsync(securityServiceRoutePattern, async route => - { - var requestUri = new Uri(route.Request.Url); - var rewrittenUri = new UriBuilder(requestUri) - { - Host = "127.0.0.1", - Port = securityServicePort - }; - - Console.WriteLine($"[browser route rewrite] {route.Request.Url} => {rewrittenUri.Uri}"); - await route.ContinueAsync(new RouteContinueOptions - { - Url = rewrittenUri.Uri.ToString() - }); - }); - } - await _browserContext.Tracing.StartAsync(new TracingStartOptions { Screenshots = true, @@ -324,4 +302,50 @@ private static async Task EnsureSecurityServiceForwarderAsync(int localPort, int } }); } + + private static async Task ProbeSecurityServiceConnectivityAsync(string? securityServiceHost, string? securityServiceLocalPortText, string? securityServicePortText) + { + var isCI = string.Equals(Environment.GetEnvironmentVariable("IsCI"), "true", StringComparison.InvariantCultureIgnoreCase); + if (!isCI) + { + return; + } + + Console.WriteLine("[browser preflight] Starting security service connectivity probe"); + Console.WriteLine($"[browser preflight] Host={securityServiceHost ?? ""}"); + Console.WriteLine($"[browser preflight] LocalPort={securityServiceLocalPortText ?? ""}"); + Console.WriteLine($"[browser preflight] HostPort={securityServicePortText ?? ""}"); + + if (!string.IsNullOrWhiteSpace(securityServiceHost)) + { + try + { + var addresses = await Dns.GetHostAddressesAsync(securityServiceHost); + Console.WriteLine($"[browser preflight] DNS={string.Join(", ", addresses.Select(address => address.ToString()))}"); + } + catch (Exception dnsException) + { + Console.WriteLine($"[browser preflight] DNS failed: {dnsException.Message}"); + } + } + + if (int.TryParse(securityServiceLocalPortText, out var localPort)) + { + try + { + using var client = new HttpClient(new HttpClientHandler + { + ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator + }); + + var probeUrl = $"https://127.0.0.1:{localPort}/.well-known/openid-configuration"; + var response = await client.GetAsync(probeUrl); + Console.WriteLine($"[browser preflight] Probe {probeUrl} => {(int)response.StatusCode} {response.StatusCode}"); + } + catch (Exception probeException) + { + Console.WriteLine($"[browser preflight] Probe failed: {probeException.Message}"); + } + } + } } From da7c8e68c2571813fc445dc7b783916dd0ba736f Mon Sep 17 00:00:00 2001 From: StuartFerguson Date: Mon, 22 Jun 2026 07:51:26 +0100 Subject: [PATCH 12/17] another tweak --- .../Features/Dashboard.feature | 2 +- EstateManagementUI.IntegrationTests/Hooks/BrowserHooks.cs | 5 +++-- EstateManagementUI.IntegrationTests/appsettings.json | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/EstateManagementUI.IntegrationTests/Features/Dashboard.feature b/EstateManagementUI.IntegrationTests/Features/Dashboard.feature index 575f9358..1ad7e8a2 100644 --- a/EstateManagementUI.IntegrationTests/Features/Dashboard.feature +++ b/EstateManagementUI.IntegrationTests/Features/Dashboard.feature @@ -31,7 +31,7 @@ Feature: Dashboard Given I create the following clients | ClientId | Name | Secret | Scopes | GrantTypes | RedirectUris | PostLogoutRedirectUris | RequireConsent | AllowOfflineAccess | ClientUri | | serviceClient | Service Client | Secret1 | transactionProcessor,fileProcessor,estateReporting | client_credentials | | | | | | - | estateUIClient | Merchant Client | Secret1 | fileProcessor,transactionProcessor,estateReporting,openid,email,profile | hybrid | https://localhost:[port]/signin-oidc | https://localhost:[port]/signout-oidc | false | true | https://[url]:[port] | + | estateUIClient | Merchant Client | Secret1 | fileProcessor,transactionProcessor,estateReporting,openid,email,profile | hybrid | https://127.0.0.1:[port]/signin-oidc | https://127.0.0.1:[port]/signout-oidc | false | true | https://127.0.0.1:[port] | Given I create the following users | Email Address | Phone Number | Given Name | Middle Name | Family Name | Claims | Roles | Password | diff --git a/EstateManagementUI.IntegrationTests/Hooks/BrowserHooks.cs b/EstateManagementUI.IntegrationTests/Hooks/BrowserHooks.cs index 2f24c1db..d9d8b042 100644 --- a/EstateManagementUI.IntegrationTests/Hooks/BrowserHooks.cs +++ b/EstateManagementUI.IntegrationTests/Hooks/BrowserHooks.cs @@ -329,7 +329,8 @@ private static async Task ProbeSecurityServiceConnectivityAsync(string? security } } - if (int.TryParse(securityServiceLocalPortText, out var localPort)) + if (int.TryParse(securityServiceLocalPortText, out var localPort) && + !string.IsNullOrWhiteSpace(securityServiceHost)) { try { @@ -338,7 +339,7 @@ private static async Task ProbeSecurityServiceConnectivityAsync(string? security ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator }); - var probeUrl = $"https://127.0.0.1:{localPort}/.well-known/openid-configuration"; + var probeUrl = $"https://{securityServiceHost}:{localPort}/.well-known/openid-configuration"; var response = await client.GetAsync(probeUrl); Console.WriteLine($"[browser preflight] Probe {probeUrl} => {(int)response.StatusCode} {response.StatusCode}"); } diff --git a/EstateManagementUI.IntegrationTests/appsettings.json b/EstateManagementUI.IntegrationTests/appsettings.json index 0f5bae89..a2c8b052 100644 --- a/EstateManagementUI.IntegrationTests/appsettings.json +++ b/EstateManagementUI.IntegrationTests/appsettings.json @@ -1,6 +1,6 @@ { "TestSettings": { - "BaseUrl": "https://localhost:5001", + "BaseUrl": "https://127.0.0.1:5001", "Browser": "Chrome", "Headless": false, "DefaultTimeout": 30000 From 985f71aaba71cc25c4b535c5681709544bf3b3b2 Mon Sep 17 00:00:00 2001 From: StuartFerguson Date: Mon, 22 Jun 2026 08:03:20 +0100 Subject: [PATCH 13/17] :| --- .../Common/DashboardPageHelper.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EstateManagementUI.IntegrationTests/Common/DashboardPageHelper.cs b/EstateManagementUI.IntegrationTests/Common/DashboardPageHelper.cs index 40790e81..8a54b45b 100644 --- a/EstateManagementUI.IntegrationTests/Common/DashboardPageHelper.cs +++ b/EstateManagementUI.IntegrationTests/Common/DashboardPageHelper.cs @@ -357,7 +357,7 @@ private async Task ClickFirstVisibleAsync(params string[] selectors) private string ResolveBaseUrl() { var hostPort = this.TestingContext.DockerHelper.GetHostPort(ContainerType.EstateManagementUI); - return $"https://localhost:{hostPort}"; + return $"https://127.0.0.1:{hostPort}"; } private async Task RunWithFailureArtifactsAsync(Func action, string context) From 25f4bdf1dcd9d3ebe76537b474f691c6f0bfac98 Mon Sep 17 00:00:00 2001 From: StuartFerguson Date: Mon, 22 Jun 2026 09:58:07 +0100 Subject: [PATCH 14/17] .. --- .../Hooks/BrowserHooks.cs | 132 +++++++++++------- 1 file changed, 80 insertions(+), 52 deletions(-) diff --git a/EstateManagementUI.IntegrationTests/Hooks/BrowserHooks.cs b/EstateManagementUI.IntegrationTests/Hooks/BrowserHooks.cs index d9d8b042..32738bb9 100644 --- a/EstateManagementUI.IntegrationTests/Hooks/BrowserHooks.cs +++ b/EstateManagementUI.IntegrationTests/Hooks/BrowserHooks.cs @@ -15,11 +15,12 @@ namespace EstateManagementUI.IntegrationTests.Hooks; public class BrowserHooks { private static IPlaywright? _playwright; - private static IBrowser? _browser; - private static IBrowserContext? _browserContext; - private static TcpListener? _securityServiceForwarder; - private static CancellationTokenSource? _forwarderCancellation; private readonly ScenarioContext _scenarioContext; + private IBrowser? _browser; + private IBrowserContext? _browserContext; + private TcpListener? _securityServiceForwarder; + private CancellationTokenSource? _forwarderCancellation; + private int? _securityServiceForwarderTargetPort; public BrowserHooks(ScenarioContext scenarioContext) { @@ -138,6 +139,14 @@ await page.ScreenshotAsync(new PageScreenshotOptions await _browserContext.CloseAsync(); _browserContext = null; } + + if (_browser != null) + { + await _browser.CloseAsync(); + _browser = null; + } + + await StopSecurityServiceForwarderAsync(); } /// @@ -146,12 +155,6 @@ await page.ScreenshotAsync(new PageScreenshotOptions [AfterTestRun] public static async Task AfterTestRun() { - if (_browser != null) - { - await _browser.CloseAsync(); - _browser = null; - } - if (_playwright != null) { _playwright.Dispose(); @@ -190,48 +193,45 @@ private async Task CreateBrowserPage() await ProbeSecurityServiceConnectivityAsync(securityServiceHost, securityServiceLocalPortText, securityServicePortText); - if (_browser == null) + _browser = browserType switch { - _browser = browserType switch + "Firefox" => await _playwright!.Firefox.LaunchAsync(new BrowserTypeLaunchOptions { - "Firefox" => await _playwright!.Firefox.LaunchAsync(new BrowserTypeLaunchOptions - { - Headless = isCI, - Args = hostResolverRules is null - ? new[] { "--ignore-certificate-errors" } - : new[] { "--ignore-certificate-errors", $"--host-resolver-rules={hostResolverRules}" } - }), - "WebKit" => await _playwright!.Webkit.LaunchAsync(new BrowserTypeLaunchOptions - { - Headless = isCI, - Args = hostResolverRules is null - ? new[] { "--ignore-certificate-errors" } - : new[] { "--ignore-certificate-errors", $"--host-resolver-rules={hostResolverRules}" } - }), - _ => await _playwright!.Chromium.LaunchAsync(new BrowserTypeLaunchOptions - { - Headless = isCI, - Args = hostResolverRules is null - ? new[] - { - "--ignore-certificate-errors", - "--no-sandbox", - "--disable-dev-shm-usage", - "--disable-gpu", - "--disable-extensions" - } - : new[] - { - "--ignore-certificate-errors", - "--no-sandbox", - "--disable-dev-shm-usage", - "--disable-gpu", - "--disable-extensions", - $"--host-resolver-rules={hostResolverRules}" - } - }) - }; - } + Headless = isCI, + Args = hostResolverRules is null + ? new[] { "--ignore-certificate-errors" } + : new[] { "--ignore-certificate-errors", $"--host-resolver-rules={hostResolverRules}" } + }), + "WebKit" => await _playwright!.Webkit.LaunchAsync(new BrowserTypeLaunchOptions + { + Headless = isCI, + Args = hostResolverRules is null + ? new[] { "--ignore-certificate-errors" } + : new[] { "--ignore-certificate-errors", $"--host-resolver-rules={hostResolverRules}" } + }), + _ => await _playwright!.Chromium.LaunchAsync(new BrowserTypeLaunchOptions + { + Headless = isCI, + Args = hostResolverRules is null + ? new[] + { + "--ignore-certificate-errors", + "--no-sandbox", + "--disable-dev-shm-usage", + "--disable-gpu", + "--disable-extensions" + } + : new[] + { + "--ignore-certificate-errors", + "--no-sandbox", + "--disable-dev-shm-usage", + "--disable-gpu", + "--disable-extensions", + $"--host-resolver-rules={hostResolverRules}" + } + }) + }; _browserContext = await _browser.NewContextAsync(new BrowserNewContextOptions { @@ -254,16 +254,19 @@ await _browserContext.Tracing.StartAsync(new TracingStartOptions return page; } - private static async Task EnsureSecurityServiceForwarderAsync(int localPort, int targetPort) + private async Task EnsureSecurityServiceForwarderAsync(int localPort, int targetPort) { - if (_securityServiceForwarder != null) + if (_securityServiceForwarder != null && _securityServiceForwarderTargetPort == targetPort) { return; } + await StopSecurityServiceForwarderAsync(); + _forwarderCancellation ??= new CancellationTokenSource(); _securityServiceForwarder = new TcpListener(IPAddress.Loopback, localPort); _securityServiceForwarder.Start(); + _securityServiceForwarderTargetPort = targetPort; _ = Task.Run(async () => { @@ -349,4 +352,29 @@ private static async Task ProbeSecurityServiceConnectivityAsync(string? security } } } + + private async Task StopSecurityServiceForwarderAsync() + { + if (_forwarderCancellation == null && _securityServiceForwarder == null) + { + return; + } + + try + { + _forwarderCancellation?.Cancel(); + _securityServiceForwarder?.Stop(); + } + catch + { + // Best effort cleanup only. + } + + _forwarderCancellation?.Dispose(); + _forwarderCancellation = null; + _securityServiceForwarder = null; + _securityServiceForwarderTargetPort = null; + + await Task.CompletedTask; + } } From 6566a970a14e40d6f071841d5e72961697d62b8b Mon Sep 17 00:00:00 2001 From: StuartFerguson Date: Mon, 22 Jun 2026 10:21:38 +0100 Subject: [PATCH 15/17] another test tweak --- .../Common/DashboardPageHelper.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/EstateManagementUI.IntegrationTests/Common/DashboardPageHelper.cs b/EstateManagementUI.IntegrationTests/Common/DashboardPageHelper.cs index 8a54b45b..e0a9988b 100644 --- a/EstateManagementUI.IntegrationTests/Common/DashboardPageHelper.cs +++ b/EstateManagementUI.IntegrationTests/Common/DashboardPageHelper.cs @@ -38,7 +38,7 @@ await RunWithFailureArtifactsAsync(async () => (await signInButton.IsVisibleAsync()).ShouldBeTrue(); Console.WriteLine($"Sign in before click: {_page.Url}"); - await signInButton.ClickAsync(); + await signInButton.ClickAsync(new LocatorClickOptions { NoWaitAfter = true }); await _page.WaitForTimeoutAsync(2000); Console.WriteLine($"Sign in after click: {_page.Url}"); Console.WriteLine($"Sign in title after click: {await _page.TitleAsync()}"); @@ -345,7 +345,7 @@ private async Task ClickFirstVisibleAsync(params string[] selectors) var first = locator.First; if (await first.IsVisibleAsync()) { - await first.ClickAsync(); + await first.ClickAsync(new LocatorClickOptions { NoWaitAfter = true }); return; } } From 1053faf6cfd7fb5ea6397dc4a1a2ddd1a4874b55 Mon Sep 17 00:00:00 2001 From: StuartFerguson Date: Mon, 22 Jun 2026 10:50:03 +0100 Subject: [PATCH 16/17] more test tweaks --- .../Common/DashboardPageHelper.cs | 27 +++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/EstateManagementUI.IntegrationTests/Common/DashboardPageHelper.cs b/EstateManagementUI.IntegrationTests/Common/DashboardPageHelper.cs index e0a9988b..d8c24910 100644 --- a/EstateManagementUI.IntegrationTests/Common/DashboardPageHelper.cs +++ b/EstateManagementUI.IntegrationTests/Common/DashboardPageHelper.cs @@ -39,7 +39,7 @@ await RunWithFailureArtifactsAsync(async () => Console.WriteLine($"Sign in before click: {_page.Url}"); await signInButton.ClickAsync(new LocatorClickOptions { NoWaitAfter = true }); - await _page.WaitForTimeoutAsync(2000); + await WaitForAuthenticationNavigationAsync(); Console.WriteLine($"Sign in after click: {_page.Url}"); Console.WriteLine($"Sign in title after click: {await _page.TitleAsync()}"); Console.WriteLine($"Sign in body after click: {await _page.Locator("body").InnerTextAsync()}"); @@ -50,14 +50,18 @@ public async Task AssertLoginScreenVisibleAsync() { await RunWithFailureArtifactsAsync(async () => { - await _page.WaitForLoadStateAsync(LoadState.DOMContentLoaded); + await WaitForAuthenticationNavigationAsync(); (await WaitForAnyVisibleAsync( "#Input_Username", "input[name='Input.Username']", + "#Input_UserName", + "input[name='Input.UserName']", "#Username", "input[name='Username']", "input[name='username']", + "input[name='UserName']", + "input[name='Email']", "input[type='email']", "input[type='text']", "input[autocomplete='username']")).ShouldBeTrue(); @@ -65,9 +69,11 @@ await RunWithFailureArtifactsAsync(async () => (await WaitForAnyVisibleAsync( "#Input_Password", "input[name='Input.Password']", + "#Input_PasswordInput", "#Password", "input[name='Password']", "input[name='password']", + "input[name='current-password']", "input[type='password']", "input[autocomplete='current-password']")).ShouldBeTrue(); }, nameof(AssertLoginScreenVisibleAsync)); @@ -354,6 +360,23 @@ private async Task ClickFirstVisibleAsync(params string[] selectors) throw new InvalidOperationException($"Could not find a visible clickable element for selectors: {string.Join(", ", selectors)}"); } + private async Task WaitForAuthenticationNavigationAsync() + { + try + { + await _page.WaitForURLAsync( + new Regex(@".*/(login|connect/authorize).*", RegexOptions.IgnoreCase), + new PageWaitForURLOptions + { + Timeout = 60000 + }); + } + catch + { + // If the URL is already where we need it, keep going and let the selector wait decide. + } + } + private string ResolveBaseUrl() { var hostPort = this.TestingContext.DockerHelper.GetHostPort(ContainerType.EstateManagementUI); From 2aa8e6611691d848cdb579291332b9e2457c300e Mon Sep 17 00:00:00 2001 From: StuartFerguson Date: Mon, 22 Jun 2026 12:41:35 +0100 Subject: [PATCH 17/17] trying something else now --- .../Common/BoostrapperExtensions.cs | 4 +- .../Hooks/BrowserHooks.cs | 142 ------------------ 2 files changed, 3 insertions(+), 143 deletions(-) diff --git a/EstateManagementUI.BlazorServer/Common/BoostrapperExtensions.cs b/EstateManagementUI.BlazorServer/Common/BoostrapperExtensions.cs index a2fb4ede..3e00e835 100644 --- a/EstateManagementUI.BlazorServer/Common/BoostrapperExtensions.cs +++ b/EstateManagementUI.BlazorServer/Common/BoostrapperExtensions.cs @@ -206,6 +206,8 @@ public static WebApplicationBuilder ConfigureLiveAuthentication(this WebApplicat { OnRedirectToIdentityProvider = context => { + context.ProtocolMessage.IssuerAddress = $"{issuerAddress}/connect/authorize"; + // Pass prompt parameter if specified in authentication properties if (context.Properties.Items.TryGetValue("prompt", out var prompt)) { @@ -273,4 +275,4 @@ public static WebApplicationBuilder RegisterSerialiser(this WebApplicationBuilde builder.Services.AddSingleton(serialiserSettings); return builder; } -} \ No newline at end of file +} diff --git a/EstateManagementUI.IntegrationTests/Hooks/BrowserHooks.cs b/EstateManagementUI.IntegrationTests/Hooks/BrowserHooks.cs index 32738bb9..d22cab76 100644 --- a/EstateManagementUI.IntegrationTests/Hooks/BrowserHooks.cs +++ b/EstateManagementUI.IntegrationTests/Hooks/BrowserHooks.cs @@ -1,9 +1,6 @@ using Microsoft.Playwright; using Reqnroll; using System.Net; -using System.Net.Http; -using System.Net.Sockets; -using System.IO; using System.Text; namespace EstateManagementUI.IntegrationTests.Hooks; @@ -18,9 +15,6 @@ public class BrowserHooks private readonly ScenarioContext _scenarioContext; private IBrowser? _browser; private IBrowserContext? _browserContext; - private TcpListener? _securityServiceForwarder; - private CancellationTokenSource? _forwarderCancellation; - private int? _securityServiceForwarderTargetPort; public BrowserHooks(ScenarioContext scenarioContext) { @@ -146,7 +140,6 @@ await page.ScreenshotAsync(new PageScreenshotOptions _browser = null; } - await StopSecurityServiceForwarderAsync(); } /// @@ -173,7 +166,6 @@ private async Task CreateBrowserPage() "true", StringComparison.InvariantCultureIgnoreCase); var securityServiceHost = Environment.GetEnvironmentVariable("SecurityServiceContainerName"); - var securityServiceLocalPortText = Environment.GetEnvironmentVariable("SecurityServiceLocalPort"); var securityServicePortText = Environment.GetEnvironmentVariable("SecurityServicePort"); var hostResolverRules = string.IsNullOrWhiteSpace(securityServiceHost) ? null @@ -181,17 +173,7 @@ private async Task CreateBrowserPage() Console.WriteLine($"[browser setup] Browser={browserType}, IsCI={isCI}"); Console.WriteLine($"[browser setup] SecurityServiceContainerName={securityServiceHost ?? ""}"); - Console.WriteLine($"[browser setup] SecurityServiceLocalPort={securityServiceLocalPortText ?? ""}"); Console.WriteLine($"[browser setup] SecurityServicePort={securityServicePortText ?? ""}"); - - if (int.TryParse(securityServiceLocalPortText, out var localPort) && - int.TryParse(securityServicePortText, out var targetPort) && - localPort != targetPort) - { - await EnsureSecurityServiceForwarderAsync(localPort, targetPort); - } - - await ProbeSecurityServiceConnectivityAsync(securityServiceHost, securityServiceLocalPortText, securityServicePortText); _browser = browserType switch { @@ -253,128 +235,4 @@ await _browserContext.Tracing.StartAsync(new TracingStartOptions return page; } - - private async Task EnsureSecurityServiceForwarderAsync(int localPort, int targetPort) - { - if (_securityServiceForwarder != null && _securityServiceForwarderTargetPort == targetPort) - { - return; - } - - await StopSecurityServiceForwarderAsync(); - - _forwarderCancellation ??= new CancellationTokenSource(); - _securityServiceForwarder = new TcpListener(IPAddress.Loopback, localPort); - _securityServiceForwarder.Start(); - _securityServiceForwarderTargetPort = targetPort; - - _ = Task.Run(async () => - { - while (!_forwarderCancellation.IsCancellationRequested) - { - TcpClient? inboundClient = null; - TcpClient? outboundClient = null; - - try - { - inboundClient = await _securityServiceForwarder.AcceptTcpClientAsync(_forwarderCancellation.Token); - outboundClient = new TcpClient(); - await outboundClient.ConnectAsync(IPAddress.Loopback, targetPort, _forwarderCancellation.Token); - - var inboundStream = inboundClient.GetStream(); - var outboundStream = outboundClient.GetStream(); - - var inboundToOutbound = inboundStream.CopyToAsync(outboundStream, _forwarderCancellation.Token); - var outboundToInbound = outboundStream.CopyToAsync(inboundStream, _forwarderCancellation.Token); - - await Task.WhenAny(Task.WhenAll(inboundToOutbound, outboundToInbound), Task.Delay(Timeout.Infinite, _forwarderCancellation.Token)); - } - catch (OperationCanceledException) - { - break; - } - catch - { - // Ignore connection churn; the browser may open and close several sockets during navigation. - } - finally - { - outboundClient?.Close(); - inboundClient?.Close(); - } - } - }); - } - - private static async Task ProbeSecurityServiceConnectivityAsync(string? securityServiceHost, string? securityServiceLocalPortText, string? securityServicePortText) - { - var isCI = string.Equals(Environment.GetEnvironmentVariable("IsCI"), "true", StringComparison.InvariantCultureIgnoreCase); - if (!isCI) - { - return; - } - - Console.WriteLine("[browser preflight] Starting security service connectivity probe"); - Console.WriteLine($"[browser preflight] Host={securityServiceHost ?? ""}"); - Console.WriteLine($"[browser preflight] LocalPort={securityServiceLocalPortText ?? ""}"); - Console.WriteLine($"[browser preflight] HostPort={securityServicePortText ?? ""}"); - - if (!string.IsNullOrWhiteSpace(securityServiceHost)) - { - try - { - var addresses = await Dns.GetHostAddressesAsync(securityServiceHost); - Console.WriteLine($"[browser preflight] DNS={string.Join(", ", addresses.Select(address => address.ToString()))}"); - } - catch (Exception dnsException) - { - Console.WriteLine($"[browser preflight] DNS failed: {dnsException.Message}"); - } - } - - if (int.TryParse(securityServiceLocalPortText, out var localPort) && - !string.IsNullOrWhiteSpace(securityServiceHost)) - { - try - { - using var client = new HttpClient(new HttpClientHandler - { - ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator - }); - - var probeUrl = $"https://{securityServiceHost}:{localPort}/.well-known/openid-configuration"; - var response = await client.GetAsync(probeUrl); - Console.WriteLine($"[browser preflight] Probe {probeUrl} => {(int)response.StatusCode} {response.StatusCode}"); - } - catch (Exception probeException) - { - Console.WriteLine($"[browser preflight] Probe failed: {probeException.Message}"); - } - } - } - - private async Task StopSecurityServiceForwarderAsync() - { - if (_forwarderCancellation == null && _securityServiceForwarder == null) - { - return; - } - - try - { - _forwarderCancellation?.Cancel(); - _securityServiceForwarder?.Stop(); - } - catch - { - // Best effort cleanup only. - } - - _forwarderCancellation?.Dispose(); - _forwarderCancellation = null; - _securityServiceForwarder = null; - _securityServiceForwarderTargetPort = null; - - await Task.CompletedTask; - } }