Skip to content

Commit dfada4a

Browse files
committed
fix(@angular/build): scope CHROME_BIN executable path to individual playwright instances
Previously, if CHROME_BIN was set in the environment and a user ran tests targeting the Playwright provider, the path was applied to the global Playwright launch options. This caused tests to crash if a user requested non-Chromium browsers (like Firefox) alongside Chromium, because Playwright would incorrectly attempt to launch the Chrome binary for the Firefox instance. This commit updates the browser configuration to map instances before providers are initialized, and selectively injects `launchOptions: { executablePath: process.env.CHROME_BIN }` at the individual instance level for chrome and chromium only. This restores parity where users can maintain CHROME_BIN variables while safely invoking alternative browsers.
1 parent 685ebae commit dfada4a

File tree

2 files changed

+69
-6
lines changed

2 files changed

+69
-6
lines changed

packages/angular/build/src/builders/unit-test/runners/vitest/browser-provider.ts

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,10 @@ export async function setupBrowserConfiguration(
7979
);
8080
}
8181

82+
const instances = browsers.map(
83+
(b) => normalizeBrowserName(b) as { browser: string; headless: boolean; provider?: import('vitest/node').BrowserProviderOption },
84+
);
85+
8286
let provider: import('vitest/node').BrowserProviderOption | undefined;
8387
if (providerName) {
8488
const providerPackage = `@vitest/browser-${providerName}`;
@@ -90,17 +94,24 @@ export async function setupBrowserConfiguration(
9094
if (typeof providerFactory === 'function') {
9195
if (providerName === 'playwright') {
9296
const executablePath = process.env['CHROME_BIN'];
97+
9398
provider = providerFactory({
94-
launchOptions: executablePath
95-
? {
96-
executablePath,
97-
}
98-
: undefined,
9999
contextOptions: {
100100
// Enables `prefer-color-scheme` for Vitest browser instead of `light`
101101
colorScheme: null,
102102
},
103103
});
104+
105+
if (executablePath) {
106+
for (const instance of instances) {
107+
if (instance.browser === 'chrome' || instance.browser === 'chromium') {
108+
instance.provider = providerFactory({
109+
launchOptions: { executablePath },
110+
contextOptions: { colorScheme: null },
111+
});
112+
}
113+
}
114+
}
104115
} else {
105116
provider = providerFactory();
106117
}
@@ -133,7 +144,6 @@ export async function setupBrowserConfiguration(
133144
}
134145

135146
const isCI = !!process.env['CI'];
136-
const instances = browsers.map(normalizeBrowserName);
137147
const messages: string[] = [];
138148

139149
if (providerName === 'preview') {

packages/angular/build/src/builders/unit-test/runners/vitest/browser-provider_spec.ts

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,4 +215,57 @@ describe('setupBrowserConfiguration', () => {
215215
'The "headless" option is unnecessary as all browsers are already configured to run in headless mode.',
216216
]);
217217
});
218+
219+
describe('CHROME_BIN usage', () => {
220+
let originalChromeBin: string | undefined;
221+
222+
beforeEach(() => {
223+
originalChromeBin = process.env['CHROME_BIN'];
224+
process.env['CHROME_BIN'] = '/custom/path/to/chrome';
225+
});
226+
227+
afterEach(() => {
228+
if (originalChromeBin === undefined) {
229+
delete process.env['CHROME_BIN'];
230+
} else {
231+
process.env['CHROME_BIN'] = originalChromeBin;
232+
}
233+
});
234+
235+
it('should set executablePath on the individual chrome instance', async () => {
236+
const { browser } = await setupBrowserConfiguration(
237+
['ChromeHeadless', 'Chromium'],
238+
undefined,
239+
false,
240+
workspaceRoot,
241+
undefined,
242+
);
243+
244+
// Verify the global provider does NOT have executablePath
245+
expect((browser?.provider as any)?.options?.launchOptions?.executablePath).toBeUndefined();
246+
247+
// Verify the individual instances have executablePath
248+
expect((browser?.instances?.[0]?.provider as any)?.options?.launchOptions?.executablePath).toBe('/custom/path/to/chrome');
249+
expect((browser?.instances?.[1]?.provider as any)?.options?.launchOptions?.executablePath).toBe('/custom/path/to/chrome');
250+
});
251+
252+
it('should set executablePath for chrome instances but not for others when mixed browsers are requested', async () => {
253+
const { browser } = await setupBrowserConfiguration(
254+
['ChromeHeadless', 'Firefox'],
255+
undefined,
256+
false,
257+
workspaceRoot,
258+
undefined,
259+
);
260+
261+
// Verify the global provider does NOT have executablePath
262+
expect((browser?.provider as any)?.options?.launchOptions?.executablePath).toBeUndefined();
263+
264+
// Verify chrome gets it
265+
expect((browser?.instances?.[0]?.provider as any)?.options?.launchOptions?.executablePath).toBe('/custom/path/to/chrome');
266+
267+
// Verify firefox does not
268+
expect(browser?.instances?.[1]?.provider).toBeUndefined();
269+
});
270+
});
218271
});

0 commit comments

Comments
 (0)