From 2d87fec7f4e7ce27fb26d11c1a8681e5351f286a Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Thu, 18 Jun 2026 11:50:33 +0200 Subject: [PATCH 1/3] rebase --- .azure/pipelines/components-e2e-tests.yml | 13 ++++++ .../jobs/components-e2e-test-job.yml | 44 ++++++++++++------- .../src/Services/LazyAssemblyLoader.cs | 19 ++++---- ...soft.AspNetCore.Components.E2ETests.csproj | 11 +++++ .../GlobalizationWasmApp/wwwroot/index.html | 10 ++++- 5 files changed, 73 insertions(+), 24 deletions(-) diff --git a/.azure/pipelines/components-e2e-tests.yml b/.azure/pipelines/components-e2e-tests.yml index c97ab3b597e4..48b35f2752fb 100644 --- a/.azure/pipelines/components-e2e-tests.yml +++ b/.azure/pipelines/components-e2e-tests.yml @@ -49,4 +49,17 @@ variables: - template: /eng/common/templates/variables/pool-providers.yml jobs: +# CoreCLR runtime E2E tests (UseMonoRuntime=false) — runs first for faster feedback +# Threading tests are excluded via the csproj when UseMonoRuntime=false - template: jobs/components-e2e-test-job.yml + parameters: + runtimeName: CoreCLR + runtimeBuildArgs: '/p:UseMonoRuntime=false' + buildRestoreArgs: '' + minimumTestCount: 500 + +# Mono runtime (default) E2E tests +- template: jobs/components-e2e-test-job.yml + parameters: + runtimeName: Mono + minimumTestCount: 1000 diff --git a/.azure/pipelines/jobs/components-e2e-test-job.yml b/.azure/pipelines/jobs/components-e2e-test-job.yml index 7d315099c994..cfc36de350fe 100644 --- a/.azure/pipelines/jobs/components-e2e-test-job.yml +++ b/.azure/pipelines/jobs/components-e2e-test-job.yml @@ -2,11 +2,25 @@ # Shared job definition for Components E2E tests. # Used by both components-e2e-tests.yml and components-e2e-tests-internal.yml. +parameters: +- name: runtimeName + type: string + default: 'Mono' +- name: runtimeBuildArgs + type: string + default: '' +- name: buildRestoreArgs + type: string + default: '--no-restore' +- name: minimumTestCount + type: number + default: 1000 + jobs: - template: default-build.yml parameters: - jobName: Components_E2E_Test - jobDisplayName: "Test: Blazor E2E tests on Linux" + jobName: Components_E2E_Test_${{ parameters.runtimeName }} + jobDisplayName: "Test: Blazor E2E tests on Linux (${{ parameters.runtimeName }})" agentOs: Linux use1ESUbuntu: true isAzDOTestingJob: true @@ -30,14 +44,14 @@ jobs: condition: ne(variables.NODE_MODULES_CACHE_HIT, 'true') - script: npm run build displayName: Build JS - - script: .dotnet/dotnet build ./src/Components/test/E2ETest -c $(BuildConfiguration) --no-restore - displayName: Build + - script: .dotnet/dotnet build ./src/Components/test/E2ETest -c $(BuildConfiguration) ${{ parameters.buildRestoreArgs }} ${{ parameters.runtimeBuildArgs }} + displayName: Build (${{ parameters.runtimeName }}) - script: | set -eo pipefail .dotnet/dotnet test ./src/Components/test/E2ETest \ -c $(BuildConfiguration) \ - --no-build \ + --no-build ${{ parameters.runtimeBuildArgs }} \ --filter 'Quarantined!=true|Quarantined=false' \ -p:VsTestUseMSBuildOutput=false \ --logger:"trx%3BLogFileName=Microsoft.AspNetCore.Components.E2ETests.trx" \ @@ -55,44 +69,44 @@ jobs: # Check total tests run to detect abnormalities. In case the number of tests changes significantly, we should adjust the threshold. # Extract total from the summary line "Failed: xx, Passed: yy, Skipped: zz, Total: NNN, Duration: ..." total=$(sed -nE 's/.*Failed:[[:space:]]*[0-9]+,[[:space:]]*Passed:[[:space:]]*[0-9]+,[[:space:]]*Skipped:[[:space:]]*[0-9]+,[[:space:]]*Total:[[:space:]]*([0-9]+).*/\1/p' e2e-test-output.log) - min_total=1000 + min_total=${{ parameters.minimumTestCount }} if [ -z "$total" ] || [ "$total" -lt "$min_total" ] then echo "##vso[task.logissue type=error] Insufficient total test count: $total. We expect at least $min_total tests to run." exit 1 fi - displayName: Run E2E tests - - script: .dotnet/dotnet test ./src/Components/test/E2ETest -c $(BuildConfiguration) --no-build --filter 'Quarantined=true' -p:RunQuarantinedTests=true + displayName: Run E2E tests (${{ parameters.runtimeName }}) + - script: .dotnet/dotnet test ./src/Components/test/E2ETest -c $(BuildConfiguration) --no-build ${{ parameters.runtimeBuildArgs }} --filter 'Quarantined=true' -p:RunQuarantinedTests=true -p:VsTestUseMSBuildOutput=false --logger:"trx%3BLogFileName=Microsoft.AspNetCore.Components.E2ETests.trx" --logger:"html%3BLogFileName=Microsoft.AspNetCore.Components.E2ETests.html" --results-directory $(Build.SourcesDirectory)/artifacts/TestResults/$(BuildConfiguration)/Quarantined - displayName: Run Quarantined E2E tests + displayName: Run Quarantined E2E tests (${{ parameters.runtimeName }}) continueOnError: true - task: PublishTestResults@2 - displayName: Publish E2E Test Results + displayName: Publish E2E Test Results (${{ parameters.runtimeName }}) inputs: testResultsFormat: 'VSTest' testResultsFiles: '*.trx' searchFolder: '$(Build.SourcesDirectory)/artifacts/TestResults/$(BuildConfiguration)/Unquarantined' - testRunTitle: ComponentsE2E-$(AgentOsName)-$(BuildConfiguration)-xunit + testRunTitle: ComponentsE2E-${{ parameters.runtimeName }}-$(AgentOsName)-$(BuildConfiguration)-xunit condition: always() - task: PublishTestResults@2 - displayName: Publish Quarantined E2E Test Results + displayName: Publish Quarantined E2E Test Results (${{ parameters.runtimeName }}) inputs: testResultsFormat: 'VSTest' testResultsFiles: '*.trx' searchFolder: '$(Build.SourcesDirectory)/artifacts/TestResults/$(BuildConfiguration)/Quarantined' - testRunTitle: Quarantine-$(AgentOsName)-$(BuildConfiguration)-xunit + testRunTitle: Quarantine-${{ parameters.runtimeName }}-$(AgentOsName)-$(BuildConfiguration)-xunit mergeTestResults: true condition: always() artifacts: - - name: Components_E2E_Logs + - name: Components_E2E_${{ parameters.runtimeName }}_Logs path: artifacts/log/ publishOnError: true includeForks: true - - name: Components_E2E_Test_Logs + - name: Components_E2E_${{ parameters.runtimeName }}_Test_Logs path: '$(Build.SourcesDirectory)/artifacts/TestResults/$(BuildConfiguration)' includeForks: true publishOnError: true diff --git a/src/Components/WebAssembly/WebAssembly/src/Services/LazyAssemblyLoader.cs b/src/Components/WebAssembly/WebAssembly/src/Services/LazyAssemblyLoader.cs index 16a5ce5cb302..728dd25c1122 100644 --- a/src/Components/WebAssembly/WebAssembly/src/Services/LazyAssemblyLoader.cs +++ b/src/Components/WebAssembly/WebAssembly/src/Services/LazyAssemblyLoader.cs @@ -72,24 +72,27 @@ private static async Task> LoadAssembliesInClientAsync(IEn var loadedAssemblies = new List(); var pendingLoads = newAssembliesToLoad.Select(LazyAssemblyLoaderInterop.LoadLazyAssembly); + // this will download the files and install them into memory + // it would not load them into the VM until we call LoadFromAssemblyName below var loadedStatus = await Task.WhenAll(pendingLoads); int i = 0; - List? allAssemblies = null; foreach (var loaded in loadedStatus) { if (loaded) { - if (allAssemblies == null) + var assemblyName = Path.GetFileNameWithoutExtension(newAssembliesToLoad[i]); + try { - allAssemblies = AssemblyLoadContext.Default.Assemblies.ToList(); + var assembly = AssemblyLoadContext.Default.LoadFromAssemblyName(new AssemblyName(assemblyName)); + if (assembly != null) + { + loadedAssemblies.Add(assembly); + } } - - var assemblyName = Path.GetFileNameWithoutExtension(newAssembliesToLoad[i]); - var assembly = AssemblyLoadContext.Default.Assemblies.FirstOrDefault(a => a.GetName().Name == assemblyName); - if (assembly != null) + catch (FileNotFoundException) { - loadedAssemblies.Add(assembly); + // no op } } diff --git a/src/Components/test/E2ETest/Microsoft.AspNetCore.Components.E2ETests.csproj b/src/Components/test/E2ETest/Microsoft.AspNetCore.Components.E2ETests.csproj index 9d23209e37ef..d361cf25015c 100644 --- a/src/Components/test/E2ETest/Microsoft.AspNetCore.Components.E2ETests.csproj +++ b/src/Components/test/E2ETest/Microsoft.AspNetCore.Components.E2ETests.csproj @@ -42,6 +42,17 @@ + + + + + + + + + + diff --git a/src/Components/test/testassets/GlobalizationWasmApp/wwwroot/index.html b/src/Components/test/testassets/GlobalizationWasmApp/wwwroot/index.html index 7201ad0e358b..558700b251ec 100644 --- a/src/Components/test/testassets/GlobalizationWasmApp/wwwroot/index.html +++ b/src/Components/test/testassets/GlobalizationWasmApp/wwwroot/index.html @@ -13,7 +13,15 @@ (function(){ const search = new window.URLSearchParams(window.location.search); const culture = search.get('culture'); - Blazor.start({ applicationCulture: culture }); + Blazor.start({ + applicationCulture: culture, + // GOTCHA: Workaround until https://github.com/dotnet/runtime/pull/129221 + configureRuntime: dotnet => { + if (culture) { + dotnet.withEnvironmentVariable('LANG', `${culture}.UTF-8`); + } + } + }); })(); From e606ea3b26c98ab1de1c30e032fd843088b51917 Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Sun, 21 Jun 2026 13:29:15 +0200 Subject: [PATCH 2/3] revert LANG workaround --- .../testassets/GlobalizationWasmApp/wwwroot/index.html | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/src/Components/test/testassets/GlobalizationWasmApp/wwwroot/index.html b/src/Components/test/testassets/GlobalizationWasmApp/wwwroot/index.html index 558700b251ec..7201ad0e358b 100644 --- a/src/Components/test/testassets/GlobalizationWasmApp/wwwroot/index.html +++ b/src/Components/test/testassets/GlobalizationWasmApp/wwwroot/index.html @@ -13,15 +13,7 @@ (function(){ const search = new window.URLSearchParams(window.location.search); const culture = search.get('culture'); - Blazor.start({ - applicationCulture: culture, - // GOTCHA: Workaround until https://github.com/dotnet/runtime/pull/129221 - configureRuntime: dotnet => { - if (culture) { - dotnet.withEnvironmentVariable('LANG', `${culture}.UTF-8`); - } - } - }); + Blazor.start({ applicationCulture: culture }); })(); From 39bab28bd4f19266ad87570c30fd1e10402801e9 Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Thu, 9 Jul 2026 15:52:46 +0200 Subject: [PATCH 3/3] cleanup --- .azure/pipelines/components-e2e-tests.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.azure/pipelines/components-e2e-tests.yml b/.azure/pipelines/components-e2e-tests.yml index 48b35f2752fb..d8984fcada02 100644 --- a/.azure/pipelines/components-e2e-tests.yml +++ b/.azure/pipelines/components-e2e-tests.yml @@ -49,8 +49,7 @@ variables: - template: /eng/common/templates/variables/pool-providers.yml jobs: -# CoreCLR runtime E2E tests (UseMonoRuntime=false) — runs first for faster feedback -# Threading tests are excluded via the csproj when UseMonoRuntime=false +# CoreCLR runtime E2E tests (UseMonoRuntime=false) - template: jobs/components-e2e-test-job.yml parameters: runtimeName: CoreCLR