Skip to content

Commit 754ee13

Browse files
feat(electron): accept BrowserContextOptions in electron.launch (#6621)
1 parent 972f0ec commit 754ee13

File tree

8 files changed

+302
-14
lines changed

8 files changed

+302
-14
lines changed

docs/src/api/class-electron.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,3 +76,20 @@ Specifies environment variables that will be visible to Electron. Defaults to `p
7676
- `timeout` <[float]>
7777

7878
Maximum time in milliseconds to wait for the application to start. Defaults to `30000` (30 seconds). Pass `0` to disable timeout.
79+
80+
### option: Electron.launch.acceptdownloads = %%-context-option-acceptdownloads-%%
81+
### option: Electron.launch.bypassCSP = %%-context-option-bypasscsp-%%
82+
### option: Electron.launch.colorScheme = %%-context-option-colorscheme-%%
83+
### option: Electron.launch.extraHTTPHeaders = %%-context-option-extrahttpheaders-%%
84+
### option: Electron.launch.geolocation = %%-context-option-geolocation-%%
85+
### option: Electron.launch.httpcredentials = %%-context-option-httpcredentials-%%
86+
### option: Electron.launch.ignoreHTTPSErrors = %%-context-option-ignorehttpserrors-%%
87+
### option: Electron.launch.locale = %%-context-option-locale-%%
88+
### option: Electron.launch.offline = %%-context-option-offline-%%
89+
### option: Electron.launch.recordhar = %%-context-option-recordhar-%%
90+
### option: Electron.launch.recordhar.path = %%-context-option-recordhar-path-%%
91+
### option: Electron.launch.recordhar.recordHarOmitContent = %%-context-option-recordhar-omit-content-%%
92+
### option: Electron.launch.recordvideo = %%-context-option-recordvideo-%%
93+
### option: Electron.launch.recordvideo.dir = %%-context-option-recordvideo-dir-%%
94+
### option: Electron.launch.recordvideo.size = %%-context-option-recordvideo-size-%%
95+
### option: Electron.launch.timezoneId = %%-context-option-timezoneid-%%

src/client/electron.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,17 +19,19 @@ import * as structs from '../../types/structs';
1919
import * as api from '../../types/types';
2020
import * as channels from '../protocol/channels';
2121
import { TimeoutSettings } from '../utils/timeoutSettings';
22+
import { headersObjectToArray } from '../utils/utils';
2223
import { BrowserContext } from './browserContext';
2324
import { ChannelOwner } from './channelOwner';
2425
import { envObjectToArray } from './clientHelper';
2526
import { Events } from './events';
2627
import { JSHandle, parseResult, serializeArgument } from './jsHandle';
2728
import { Page } from './page';
28-
import { Env, WaitForEventOptions } from './types';
29+
import { Env, WaitForEventOptions, Headers } from './types';
2930
import { Waiter } from './waiter';
3031

31-
type ElectronOptions = Omit<channels.ElectronLaunchOptions, 'env'> & {
32+
type ElectronOptions = Omit<channels.ElectronLaunchOptions, 'env'|'extraHTTPHeaders'> & {
3233
env?: Env,
34+
extraHTTPHeaders?: Headers,
3335
};
3436

3537
type ElectronAppType = typeof import('electron');
@@ -48,6 +50,7 @@ export class Electron extends ChannelOwner<channels.ElectronChannel, channels.El
4850
const params: channels.ElectronLaunchParams = {
4951
sdkLanguage: 'javascript',
5052
...options,
53+
extraHTTPHeaders: options.extraHTTPHeaders && headersObjectToArray(options.extraHTTPHeaders),
5154
env: envObjectToArray(options.env ? options.env : process.env),
5255
};
5356
return ElectronApplication.from((await channel.launch(params)).electronApplication);

src/protocol/channels.ts

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2555,13 +2555,69 @@ export type ElectronLaunchParams = {
25552555
cwd?: string,
25562556
env?: NameValue[],
25572557
timeout?: number,
2558+
acceptDownloads?: boolean,
2559+
bypassCSP?: boolean,
2560+
colorScheme?: 'dark' | 'light' | 'no-preference',
2561+
extraHTTPHeaders?: NameValue[],
2562+
geolocation?: {
2563+
longitude: number,
2564+
latitude: number,
2565+
accuracy?: number,
2566+
},
2567+
httpCredentials?: {
2568+
username: string,
2569+
password: string,
2570+
},
2571+
ignoreHTTPSErrors?: boolean,
2572+
locale?: string,
2573+
offline?: boolean,
2574+
recordHar?: {
2575+
omitContent?: boolean,
2576+
path: string,
2577+
},
2578+
recordVideo?: {
2579+
dir: string,
2580+
size?: {
2581+
width: number,
2582+
height: number,
2583+
},
2584+
},
2585+
timezoneId?: string,
25582586
};
25592587
export type ElectronLaunchOptions = {
25602588
executablePath?: string,
25612589
args?: string[],
25622590
cwd?: string,
25632591
env?: NameValue[],
25642592
timeout?: number,
2593+
acceptDownloads?: boolean,
2594+
bypassCSP?: boolean,
2595+
colorScheme?: 'dark' | 'light' | 'no-preference',
2596+
extraHTTPHeaders?: NameValue[],
2597+
geolocation?: {
2598+
longitude: number,
2599+
latitude: number,
2600+
accuracy?: number,
2601+
},
2602+
httpCredentials?: {
2603+
username: string,
2604+
password: string,
2605+
},
2606+
ignoreHTTPSErrors?: boolean,
2607+
locale?: string,
2608+
offline?: boolean,
2609+
recordHar?: {
2610+
omitContent?: boolean,
2611+
path: string,
2612+
},
2613+
recordVideo?: {
2614+
dir: string,
2615+
size?: {
2616+
width: number,
2617+
height: number,
2618+
},
2619+
},
2620+
timezoneId?: string,
25652621
};
25662622
export type ElectronLaunchResult = {
25672623
electronApplication: ElectronApplicationChannel,

src/protocol/protocol.yml

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2094,6 +2094,47 @@ Electron:
20942094
type: array?
20952095
items: NameValue
20962096
timeout: number?
2097+
acceptDownloads: boolean?
2098+
bypassCSP: boolean?
2099+
colorScheme:
2100+
type: enum?
2101+
literals:
2102+
- dark
2103+
- light
2104+
- no-preference
2105+
extraHTTPHeaders:
2106+
type: array?
2107+
items: NameValue
2108+
geolocation:
2109+
type: object?
2110+
properties:
2111+
longitude: number
2112+
latitude: number
2113+
accuracy: number?
2114+
httpCredentials:
2115+
type: object?
2116+
properties:
2117+
username: string
2118+
password: string
2119+
ignoreHTTPSErrors: boolean?
2120+
locale: string?
2121+
offline: boolean?
2122+
recordHar:
2123+
type: object?
2124+
properties:
2125+
omitContent: boolean?
2126+
path: string
2127+
recordVideo:
2128+
type: object?
2129+
properties:
2130+
dir: string
2131+
size:
2132+
type: object?
2133+
properties:
2134+
width: number
2135+
height: number
2136+
timezoneId: string?
2137+
20972138
returns:
20982139
electronApplication: ElectronApplication
20992140

src/protocol/validator.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -973,6 +973,34 @@ export function createScheme(tChannel: (name: string) => Validator): Scheme {
973973
cwd: tOptional(tString),
974974
env: tOptional(tArray(tType('NameValue'))),
975975
timeout: tOptional(tNumber),
976+
acceptDownloads: tOptional(tBoolean),
977+
bypassCSP: tOptional(tBoolean),
978+
colorScheme: tOptional(tEnum(['dark', 'light', 'no-preference'])),
979+
extraHTTPHeaders: tOptional(tArray(tType('NameValue'))),
980+
geolocation: tOptional(tObject({
981+
longitude: tNumber,
982+
latitude: tNumber,
983+
accuracy: tOptional(tNumber),
984+
})),
985+
httpCredentials: tOptional(tObject({
986+
username: tString,
987+
password: tString,
988+
})),
989+
ignoreHTTPSErrors: tOptional(tBoolean),
990+
locale: tOptional(tString),
991+
offline: tOptional(tBoolean),
992+
recordHar: tOptional(tObject({
993+
omitContent: tOptional(tBoolean),
994+
path: tString,
995+
})),
996+
recordVideo: tOptional(tObject({
997+
dir: tString,
998+
size: tOptional(tObject({
999+
width: tNumber,
1000+
height: tNumber,
1001+
})),
1002+
})),
1003+
timezoneId: tOptional(tString),
9761004
});
9771005
scheme.ElectronApplicationBrowserWindowParams = tObject({
9781006
page: tChannel('Page'),

src/server/electron/electron.ts

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ import * as js from '../javascript';
2222
import { Page } from '../page';
2323
import { TimeoutSettings } from '../../utils/timeoutSettings';
2424
import { WebSocketTransport } from '../transport';
25-
import * as types from '../types';
2625
import { launchProcess, envArrayToObject } from '../processLauncher';
2726
import { BrowserContext } from '../browserContext';
2827
import type {BrowserWindow} from 'electron';
@@ -33,15 +32,7 @@ import * as childProcess from 'child_process';
3332
import * as readline from 'readline';
3433
import { RecentLogsCollector } from '../../utils/debugLogger';
3534
import { internalCallMetadata, SdkObject } from '../instrumentation';
36-
37-
export type ElectronLaunchOptionsBase = {
38-
sdkLanguage: string,
39-
executablePath?: string,
40-
args?: string[],
41-
cwd?: string,
42-
env?: types.EnvArray,
43-
timeout?: number,
44-
};
35+
import * as channels from '../../protocol/channels';
4536

4637
export class ElectronApplication extends SdkObject {
4738
static Events = {
@@ -112,7 +103,7 @@ export class Electron extends SdkObject {
112103
this._playwrightOptions = playwrightOptions;
113104
}
114105

115-
async launch(options: ElectronLaunchOptionsBase): Promise<ElectronApplication> {
106+
async launch(options: channels.ElectronLaunchParams): Promise<ElectronApplication> {
116107
const {
117108
args = [],
118109
} = options;
@@ -164,7 +155,22 @@ export class Electron extends SdkObject {
164155
name: 'electron',
165156
isChromium: true,
166157
headful: true,
167-
persistent: { sdkLanguage: options.sdkLanguage, noDefaultViewport: true },
158+
persistent: {
159+
sdkLanguage: options.sdkLanguage,
160+
noDefaultViewport: true,
161+
acceptDownloads: options.acceptDownloads,
162+
bypassCSP: options.bypassCSP,
163+
colorScheme: options.colorScheme,
164+
extraHTTPHeaders: options.extraHTTPHeaders,
165+
geolocation: options.geolocation,
166+
httpCredentials: options.httpCredentials,
167+
ignoreHTTPSErrors: options.ignoreHTTPSErrors,
168+
locale: options.locale,
169+
offline: options.offline,
170+
recordHar: options.recordHar,
171+
recordVideo: options.recordVideo,
172+
timezoneId: options.timezoneId,
173+
},
168174
browserProcess,
169175
protocolLogger: helper.debugProtocolLogger(),
170176
browserLogsCollector,

tests/electron/electron-app.spec.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,3 +107,22 @@ test('should return browser window', async ({ playwright }) => {
107107
expect(await bwHandle.evaluate((bw: BrowserWindow) => bw.title)).toBe('Electron');
108108
await electronApp.close();
109109
});
110+
111+
test('should bypass csp', async ({playwright, server}) => {
112+
const app = await playwright._electron.launch({
113+
args: [require('path').join(__dirname, 'electron-app.js')],
114+
bypassCSP: true,
115+
});
116+
await app.evaluate(electron => {
117+
const window = new electron.BrowserWindow({
118+
width: 800,
119+
height: 600,
120+
});
121+
window.loadURL('about:blank');
122+
});
123+
const page = await app.firstWindow();
124+
await page.goto(server.PREFIX + '/csp.html');
125+
await page.addScriptTag({content: 'window["__injected"] = 42;'});
126+
expect(await page.evaluate('window["__injected"]')).toBe(42);
127+
await app.close();
128+
});

0 commit comments

Comments
 (0)