feat(@angular/build): support Istanbul coverage in Vitest runner#33029
feat(@angular/build): support Istanbul coverage in Vitest runner#33029clydin wants to merge 1 commit intoangular:mainfrom
Conversation
87bb020 to
f3443aa
Compare
This change enables code coverage reporting when running tests in non-Chromium browsers (like Firefox or Safari) with the Vitest runner. The system now automatically detects the best coverage provider based on the configured browsers and installed packages: - If non-Chromium browsers are configured, it selects 'istanbul'. - If only Chromium browsers are used, it selects 'istanbul' if it is the only provider package installed. - Otherwise, it defaults to 'v8'. It also respects the provider specified in the user's custom Vitest configuration.
f3443aa to
0b4f325
Compare
There was a problem hiding this comment.
Code Review
This pull request introduces support for the Istanbul coverage provider in the Vitest unit test runner, including automatic provider detection based on the target browser and installed dependencies. The review feedback identifies an opportunity to optimize browser detection logic using '.some()' for better performance and highlights several logic issues in the 'getBrowsersToCheck' function regarding CLI option priority and the handling of the 'enabled' property.
| const hasNonChromium = | ||
| browsersToCheck | ||
| .map((b) => normalizeBrowserName(b).browser) | ||
| .filter((b) => !['chrome', 'chromium', 'edge'].includes(b)).length > 0; |
There was a problem hiding this comment.
Using '.some()' is more efficient and readable than '.filter().length > 0' as it short-circuits as soon as a match is found. Additionally, performing the normalization inside the predicate avoids creating an intermediate array.
| const hasNonChromium = | |
| browsersToCheck | |
| .map((b) => normalizeBrowserName(b).browser) | |
| .filter((b) => !['chrome', 'chromium', 'edge'].includes(b)).length > 0; | |
| const hasNonChromium = browsersToCheck.some((b) => { | |
| const normalized = normalizeBrowserName(b).browser; | |
| return !['chrome', 'chromium', 'edge'].includes(normalized); | |
| }); |
| function getBrowsersToCheck( | ||
| browser: BrowserConfigOptions | undefined, | ||
| testConfigBrowser: BrowserConfigOptions | undefined, | ||
| ): string[] { | ||
| const browsersToCheck: string[] = []; | ||
|
|
||
| // 1. Check browsers passed by the Angular CLI options | ||
| const cliBrowser = browser as CustomBrowserConfigOptions | undefined; | ||
| if (cliBrowser?.instances) { | ||
| browsersToCheck.push(...cliBrowser.instances.map((i) => i.browser)); | ||
| } | ||
|
|
||
| // 2. Check browsers defined in the user's vitest.config.ts | ||
| const userBrowser = testConfigBrowser as CustomBrowserConfigOptions | undefined; | ||
| if (userBrowser) { | ||
| if (userBrowser.instances) { | ||
| browsersToCheck.push(...userBrowser.instances.map((i) => i.browser)); | ||
| } | ||
| if (userBrowser.name) { | ||
| browsersToCheck.push(userBrowser.name); | ||
| } | ||
| } | ||
|
|
||
| return browsersToCheck; | ||
| } |
There was a problem hiding this comment.
The logic for collecting browsers to check has several issues:
- It appends browsers from both the CLI options and the Vitest configuration, even though the CLI options override the configuration. This can lead to incorrect provider detection (e.g., selecting Istanbul when only Chromium browsers are actually being used via CLI).
- It doesn't check the 'enabled' property of the configuration-based browser settings.
- It misses the 'name' property for CLI-provided browser options.
The suggested implementation correctly prioritizes the CLI override and respects the 'enabled' flag while maintaining type safety for configuration properties.
function getBrowsersToCheck(
browser: BrowserConfigOptions | undefined,
testConfigBrowser: BrowserConfigOptions | undefined,
): string[] {
const activeConfig = (browser ?? (testConfigBrowser?.enabled ? testConfigBrowser : undefined)) as
| CustomBrowserConfigOptions
| undefined;
if (!activeConfig) {
return [];
}
const browsersToCheck: string[] = [];
if (activeConfig.instances) {
browsersToCheck.push(...activeConfig.instances.map((i) => i.browser));
}
if (activeConfig.name) {
browsersToCheck.push(activeConfig.name);
}
return browsersToCheck;
}References
- When refactoring code that handles configuration properties, ensure that any implicit type validation previously performed is still maintained, especially if the configuration is guaranteed to be type-safe by an upstream process.
This change enables code coverage reporting when running tests in non-Chromium browsers (like Firefox or Safari) with the Vitest runner.
The system now automatically detects the best coverage provider based on the configured browsers and installed packages: