From 1a28d9d50f259f3da5ba6d9f0ccfa5bd6286e6d0 Mon Sep 17 00:00:00 2001 From: Alan Agius <17563226+alan-agius4@users.noreply.github.com> Date: Mon, 17 Nov 2025 13:18:10 +0000 Subject: [PATCH] test: improve vitest e2e test stability and performance - Use Chrome binary from `rules_browsers` for Playwright in Vitest browser tests for hermetic testing. - Batch `ng generate` commands in e2e tests to improve performance. - Remove now redundant chromium install commands from e2e tests. --- .../runners/vitest/browser-provider.ts | 16 +++++- .../e2e/tests/vitest/larger-project.ts | 52 +++++++++++-------- .../e2e/tests/vitest/tslib-resolution.ts | 3 +- 3 files changed, 47 insertions(+), 24 deletions(-) diff --git a/packages/angular/build/src/builders/unit-test/runners/vitest/browser-provider.ts b/packages/angular/build/src/builders/unit-test/runners/vitest/browser-provider.ts index 7eed077fc03c..4f7469ebf28b 100644 --- a/packages/angular/build/src/builders/unit-test/runners/vitest/browser-provider.ts +++ b/packages/angular/build/src/builders/unit-test/runners/vitest/browser-provider.ts @@ -76,7 +76,21 @@ export async function setupBrowserConfiguration( // Validate that the imported module has the expected structure const providerFactory = providerModule[providerName]; if (typeof providerFactory === 'function') { - provider = providerFactory(); + if ( + providerName === 'playwright' && + process.env['CHROME_BIN']?.includes('rules_browsers') + ) { + // Use the Chrome binary from the 'rules_browsers' toolchain (via CHROME_BIN) + // for Playwright when available to ensure hermetic testing, preventing reliance + // on locally installed or NPM-managed browser versions. + provider = providerFactory({ + launchOptions: { + executablePath: process.env.CHROME_BIN, + }, + }); + } else { + provider = providerFactory(); + } } else { errors ??= []; errors.push( diff --git a/tests/legacy-cli/e2e/tests/vitest/larger-project.ts b/tests/legacy-cli/e2e/tests/vitest/larger-project.ts index 16d254f98a24..61b18b102c4b 100644 --- a/tests/legacy-cli/e2e/tests/vitest/larger-project.ts +++ b/tests/legacy-cli/e2e/tests/vitest/larger-project.ts @@ -12,26 +12,7 @@ export default async function () { // Each generated artifact will add one more test file. const initialTestCount = 1; - // Generate a mix of components, services, and pipes - for (let i = 0; i < artifactCount; i++) { - const type = i % 3; - const name = `test-artifact-${i}`; - let generateType; - - switch (type) { - case 0: - generateType = 'component'; - break; - case 1: - generateType = 'service'; - break; - default: - generateType = 'pipe'; - break; - } - - await ng('generate', generateType, name, '--skip-tests=false'); - } + await generateArtifactsInBatches(artifactCount); const totalTests = initialTestCount + artifactCount; const expectedMessage = new RegExp(`${totalTests} passed`); @@ -43,7 +24,6 @@ export default async function () { // Setup for browser mode await installPackage('playwright@1'); await installPackage('@vitest/browser-playwright@4'); - await exec('npx', 'playwright', 'install', 'chromium', '--only-shell'); // Run tests in browser mode const { stdout: browserStdout } = await ng( @@ -58,3 +38,33 @@ export default async function () { `Expected ${totalTests} tests to pass in browser mode.`, ); } + +async function generateArtifactsInBatches(artifactCount: number): Promise { + const BATCH_SIZE = 5; + let commands: Promise[] = []; + + for (let i = 0; i < artifactCount; i++) { + const type = i % 3; + const name = `test-artifact-${i}`; + let generateType: string; + + switch (type) { + case 0: + generateType = 'component'; + break; + case 1: + generateType = 'service'; + break; + default: + generateType = 'pipe'; + break; + } + + commands.push(ng('generate', generateType, name, '--skip-tests=false')); + + if (commands.length === BATCH_SIZE || i === artifactCount - 1) { + await Promise.all(commands); + commands = []; + } + } +} diff --git a/tests/legacy-cli/e2e/tests/vitest/tslib-resolution.ts b/tests/legacy-cli/e2e/tests/vitest/tslib-resolution.ts index d3cb95a3ef3c..759d5e2b5728 100644 --- a/tests/legacy-cli/e2e/tests/vitest/tslib-resolution.ts +++ b/tests/legacy-cli/e2e/tests/vitest/tslib-resolution.ts @@ -1,6 +1,6 @@ import { writeFile } from '../../utils/fs'; import { installPackage } from '../../utils/packages'; -import { exec, ng } from '../../utils/process'; +import { ng } from '../../utils/process'; import { applyVitestBuilder } from '../../utils/vitest'; import assert from 'node:assert'; @@ -8,7 +8,6 @@ export default async function () { await applyVitestBuilder(); await installPackage('playwright@1'); await installPackage('@vitest/browser-playwright@4'); - await exec('npx', 'playwright', 'install', 'chromium', '--only-shell'); // Add a custom decorator to trigger tslib usage await writeFile(