browserContext.js 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535
  1. "use strict";
  2. var __create = Object.create;
  3. var __defProp = Object.defineProperty;
  4. var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
  5. var __getOwnPropNames = Object.getOwnPropertyNames;
  6. var __getProtoOf = Object.getPrototypeOf;
  7. var __hasOwnProp = Object.prototype.hasOwnProperty;
  8. var __export = (target, all) => {
  9. for (var name in all)
  10. __defProp(target, name, { get: all[name], enumerable: true });
  11. };
  12. var __copyProps = (to, from, except, desc) => {
  13. if (from && typeof from === "object" || typeof from === "function") {
  14. for (let key of __getOwnPropNames(from))
  15. if (!__hasOwnProp.call(to, key) && key !== except)
  16. __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
  17. }
  18. return to;
  19. };
  20. var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
  21. // If the importer is in node compatibility mode or this is not an ESM
  22. // file that has been converted to a CommonJS file using a Babel-
  23. // compatible transform (i.e. "__esModule" has not been set), then set
  24. // "default" to the CommonJS "module.exports" for node compatibility.
  25. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
  26. mod
  27. ));
  28. var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
  29. var browserContext_exports = {};
  30. __export(browserContext_exports, {
  31. BrowserContext: () => BrowserContext,
  32. prepareBrowserContextParams: () => prepareBrowserContextParams,
  33. toClientCertificatesProtocol: () => toClientCertificatesProtocol
  34. });
  35. module.exports = __toCommonJS(browserContext_exports);
  36. var import_artifact = require("./artifact");
  37. var import_cdpSession = require("./cdpSession");
  38. var import_channelOwner = require("./channelOwner");
  39. var import_clientHelper = require("./clientHelper");
  40. var import_clock = require("./clock");
  41. var import_consoleMessage = require("./consoleMessage");
  42. var import_dialog = require("./dialog");
  43. var import_errors = require("./errors");
  44. var import_events = require("./events");
  45. var import_fetch = require("./fetch");
  46. var import_frame = require("./frame");
  47. var import_harRouter = require("./harRouter");
  48. var network = __toESM(require("./network"));
  49. var import_page = require("./page");
  50. var import_tracing = require("./tracing");
  51. var import_waiter = require("./waiter");
  52. var import_webError = require("./webError");
  53. var import_worker = require("./worker");
  54. var import_timeoutSettings = require("./timeoutSettings");
  55. var import_fileUtils = require("./fileUtils");
  56. var import_headers = require("../utils/isomorphic/headers");
  57. var import_urlMatch = require("../utils/isomorphic/urlMatch");
  58. var import_rtti = require("../utils/isomorphic/rtti");
  59. var import_stackTrace = require("../utils/isomorphic/stackTrace");
  60. class BrowserContext extends import_channelOwner.ChannelOwner {
  61. constructor(parent, type, guid, initializer) {
  62. super(parent, type, guid, initializer);
  63. this._pages = /* @__PURE__ */ new Set();
  64. this._routes = [];
  65. this._webSocketRoutes = [];
  66. // Browser is null for browser contexts created outside of normal browser, e.g. android or electron.
  67. this._browser = null;
  68. this._bindings = /* @__PURE__ */ new Map();
  69. this._forReuse = false;
  70. this._backgroundPages = /* @__PURE__ */ new Set();
  71. this._serviceWorkers = /* @__PURE__ */ new Set();
  72. this._harRecorders = /* @__PURE__ */ new Map();
  73. this._closingStatus = "none";
  74. this._harRouters = [];
  75. this._options = initializer.options;
  76. this._timeoutSettings = new import_timeoutSettings.TimeoutSettings(this._platform);
  77. this.tracing = import_tracing.Tracing.from(initializer.tracing);
  78. this.request = import_fetch.APIRequestContext.from(initializer.requestContext);
  79. this.request._timeoutSettings = this._timeoutSettings;
  80. this.clock = new import_clock.Clock(this);
  81. this._channel.on("bindingCall", ({ binding }) => this._onBinding(import_page.BindingCall.from(binding)));
  82. this._channel.on("close", () => this._onClose());
  83. this._channel.on("page", ({ page }) => this._onPage(import_page.Page.from(page)));
  84. this._channel.on("route", ({ route }) => this._onRoute(network.Route.from(route)));
  85. this._channel.on("webSocketRoute", ({ webSocketRoute }) => this._onWebSocketRoute(network.WebSocketRoute.from(webSocketRoute)));
  86. this._channel.on("backgroundPage", ({ page }) => {
  87. const backgroundPage = import_page.Page.from(page);
  88. this._backgroundPages.add(backgroundPage);
  89. this.emit(import_events.Events.BrowserContext.BackgroundPage, backgroundPage);
  90. });
  91. this._channel.on("serviceWorker", ({ worker }) => {
  92. const serviceWorker = import_worker.Worker.from(worker);
  93. serviceWorker._context = this;
  94. this._serviceWorkers.add(serviceWorker);
  95. this.emit(import_events.Events.BrowserContext.ServiceWorker, serviceWorker);
  96. });
  97. this._channel.on("console", (event) => {
  98. const consoleMessage = new import_consoleMessage.ConsoleMessage(this._platform, event);
  99. this.emit(import_events.Events.BrowserContext.Console, consoleMessage);
  100. const page = consoleMessage.page();
  101. if (page)
  102. page.emit(import_events.Events.Page.Console, consoleMessage);
  103. });
  104. this._channel.on("pageError", ({ error, page }) => {
  105. const pageObject = import_page.Page.from(page);
  106. const parsedError = (0, import_errors.parseError)(error);
  107. this.emit(import_events.Events.BrowserContext.WebError, new import_webError.WebError(pageObject, parsedError));
  108. if (pageObject)
  109. pageObject.emit(import_events.Events.Page.PageError, parsedError);
  110. });
  111. this._channel.on("dialog", ({ dialog }) => {
  112. const dialogObject = import_dialog.Dialog.from(dialog);
  113. let hasListeners = this.emit(import_events.Events.BrowserContext.Dialog, dialogObject);
  114. const page = dialogObject.page();
  115. if (page)
  116. hasListeners = page.emit(import_events.Events.Page.Dialog, dialogObject) || hasListeners;
  117. if (!hasListeners) {
  118. if (dialogObject.type() === "beforeunload")
  119. dialog.accept({}).catch(() => {
  120. });
  121. else
  122. dialog.dismiss().catch(() => {
  123. });
  124. }
  125. });
  126. this._channel.on("request", ({ request, page }) => this._onRequest(network.Request.from(request), import_page.Page.fromNullable(page)));
  127. this._channel.on("requestFailed", ({ request, failureText, responseEndTiming, page }) => this._onRequestFailed(network.Request.from(request), responseEndTiming, failureText, import_page.Page.fromNullable(page)));
  128. this._channel.on("requestFinished", (params) => this._onRequestFinished(params));
  129. this._channel.on("response", ({ response, page }) => this._onResponse(network.Response.from(response), import_page.Page.fromNullable(page)));
  130. this._channel.on("recorderEvent", ({ event, data, page, code }) => {
  131. if (event === "actionAdded")
  132. this._onRecorderEventSink?.actionAdded?.(import_page.Page.from(page), data, code);
  133. else if (event === "actionUpdated")
  134. this._onRecorderEventSink?.actionUpdated?.(import_page.Page.from(page), data, code);
  135. else if (event === "signalAdded")
  136. this._onRecorderEventSink?.signalAdded?.(import_page.Page.from(page), data);
  137. });
  138. this._closedPromise = new Promise((f) => this.once(import_events.Events.BrowserContext.Close, f));
  139. this._setEventToSubscriptionMapping(/* @__PURE__ */ new Map([
  140. [import_events.Events.BrowserContext.Console, "console"],
  141. [import_events.Events.BrowserContext.Dialog, "dialog"],
  142. [import_events.Events.BrowserContext.Request, "request"],
  143. [import_events.Events.BrowserContext.Response, "response"],
  144. [import_events.Events.BrowserContext.RequestFinished, "requestFinished"],
  145. [import_events.Events.BrowserContext.RequestFailed, "requestFailed"]
  146. ]));
  147. }
  148. static from(context) {
  149. return context._object;
  150. }
  151. static fromNullable(context) {
  152. return context ? BrowserContext.from(context) : null;
  153. }
  154. async _initializeHarFromOptions(recordHar) {
  155. if (!recordHar)
  156. return;
  157. const defaultContent = recordHar.path.endsWith(".zip") ? "attach" : "embed";
  158. await this._recordIntoHAR(recordHar.path, null, {
  159. url: recordHar.urlFilter,
  160. updateContent: recordHar.content ?? (recordHar.omitContent ? "omit" : defaultContent),
  161. updateMode: recordHar.mode ?? "full"
  162. });
  163. }
  164. _onPage(page) {
  165. this._pages.add(page);
  166. this.emit(import_events.Events.BrowserContext.Page, page);
  167. if (page._opener && !page._opener.isClosed())
  168. page._opener.emit(import_events.Events.Page.Popup, page);
  169. }
  170. _onRequest(request, page) {
  171. this.emit(import_events.Events.BrowserContext.Request, request);
  172. if (page)
  173. page.emit(import_events.Events.Page.Request, request);
  174. }
  175. _onResponse(response, page) {
  176. this.emit(import_events.Events.BrowserContext.Response, response);
  177. if (page)
  178. page.emit(import_events.Events.Page.Response, response);
  179. }
  180. _onRequestFailed(request, responseEndTiming, failureText, page) {
  181. request._failureText = failureText || null;
  182. request._setResponseEndTiming(responseEndTiming);
  183. this.emit(import_events.Events.BrowserContext.RequestFailed, request);
  184. if (page)
  185. page.emit(import_events.Events.Page.RequestFailed, request);
  186. }
  187. _onRequestFinished(params) {
  188. const { responseEndTiming } = params;
  189. const request = network.Request.from(params.request);
  190. const response = network.Response.fromNullable(params.response);
  191. const page = import_page.Page.fromNullable(params.page);
  192. request._setResponseEndTiming(responseEndTiming);
  193. this.emit(import_events.Events.BrowserContext.RequestFinished, request);
  194. if (page)
  195. page.emit(import_events.Events.Page.RequestFinished, request);
  196. if (response)
  197. response._finishedPromise.resolve(null);
  198. }
  199. async _onRoute(route) {
  200. route._context = this;
  201. const page = route.request()._safePage();
  202. const routeHandlers = this._routes.slice();
  203. for (const routeHandler of routeHandlers) {
  204. if (page?._closeWasCalled || this._closingStatus !== "none")
  205. return;
  206. if (!routeHandler.matches(route.request().url()))
  207. continue;
  208. const index = this._routes.indexOf(routeHandler);
  209. if (index === -1)
  210. continue;
  211. if (routeHandler.willExpire())
  212. this._routes.splice(index, 1);
  213. const handled = await routeHandler.handle(route);
  214. if (!this._routes.length)
  215. this._updateInterceptionPatterns({ internal: true }).catch(() => {
  216. });
  217. if (handled)
  218. return;
  219. }
  220. await route._innerContinue(
  221. true
  222. /* isFallback */
  223. ).catch(() => {
  224. });
  225. }
  226. async _onWebSocketRoute(webSocketRoute) {
  227. const routeHandler = this._webSocketRoutes.find((route) => route.matches(webSocketRoute.url()));
  228. if (routeHandler)
  229. await routeHandler.handle(webSocketRoute);
  230. else
  231. webSocketRoute.connectToServer();
  232. }
  233. async _onBinding(bindingCall) {
  234. const func = this._bindings.get(bindingCall._initializer.name);
  235. if (!func)
  236. return;
  237. await bindingCall.call(func);
  238. }
  239. setDefaultNavigationTimeout(timeout) {
  240. this._timeoutSettings.setDefaultNavigationTimeout(timeout);
  241. }
  242. setDefaultTimeout(timeout) {
  243. this._timeoutSettings.setDefaultTimeout(timeout);
  244. }
  245. browser() {
  246. return this._browser;
  247. }
  248. pages() {
  249. return [...this._pages];
  250. }
  251. async newPage() {
  252. if (this._ownerPage)
  253. throw new Error("Please use browser.newContext()");
  254. return import_page.Page.from((await this._channel.newPage()).page);
  255. }
  256. async cookies(urls) {
  257. if (!urls)
  258. urls = [];
  259. if (urls && typeof urls === "string")
  260. urls = [urls];
  261. return (await this._channel.cookies({ urls })).cookies;
  262. }
  263. async addCookies(cookies) {
  264. await this._channel.addCookies({ cookies });
  265. }
  266. async clearCookies(options = {}) {
  267. await this._channel.clearCookies({
  268. name: (0, import_rtti.isString)(options.name) ? options.name : void 0,
  269. nameRegexSource: (0, import_rtti.isRegExp)(options.name) ? options.name.source : void 0,
  270. nameRegexFlags: (0, import_rtti.isRegExp)(options.name) ? options.name.flags : void 0,
  271. domain: (0, import_rtti.isString)(options.domain) ? options.domain : void 0,
  272. domainRegexSource: (0, import_rtti.isRegExp)(options.domain) ? options.domain.source : void 0,
  273. domainRegexFlags: (0, import_rtti.isRegExp)(options.domain) ? options.domain.flags : void 0,
  274. path: (0, import_rtti.isString)(options.path) ? options.path : void 0,
  275. pathRegexSource: (0, import_rtti.isRegExp)(options.path) ? options.path.source : void 0,
  276. pathRegexFlags: (0, import_rtti.isRegExp)(options.path) ? options.path.flags : void 0
  277. });
  278. }
  279. async grantPermissions(permissions, options) {
  280. await this._channel.grantPermissions({ permissions, ...options });
  281. }
  282. async clearPermissions() {
  283. await this._channel.clearPermissions();
  284. }
  285. async setGeolocation(geolocation) {
  286. await this._channel.setGeolocation({ geolocation: geolocation || void 0 });
  287. }
  288. async setExtraHTTPHeaders(headers) {
  289. network.validateHeaders(headers);
  290. await this._channel.setExtraHTTPHeaders({ headers: (0, import_headers.headersObjectToArray)(headers) });
  291. }
  292. async setOffline(offline) {
  293. await this._channel.setOffline({ offline });
  294. }
  295. async setHTTPCredentials(httpCredentials) {
  296. await this._channel.setHTTPCredentials({ httpCredentials: httpCredentials || void 0 });
  297. }
  298. async addInitScript(script, arg) {
  299. const source = await (0, import_clientHelper.evaluationScript)(this._platform, script, arg);
  300. await this._channel.addInitScript({ source });
  301. }
  302. async exposeBinding(name, callback, options = {}) {
  303. await this._channel.exposeBinding({ name, needsHandle: options.handle });
  304. this._bindings.set(name, callback);
  305. }
  306. async exposeFunction(name, callback) {
  307. await this._channel.exposeBinding({ name });
  308. const binding = (source, ...args) => callback(...args);
  309. this._bindings.set(name, binding);
  310. }
  311. async route(url, handler, options = {}) {
  312. this._routes.unshift(new network.RouteHandler(this._platform, this._options.baseURL, url, handler, options.times));
  313. await this._updateInterceptionPatterns({ title: "Route requests" });
  314. }
  315. async routeWebSocket(url, handler) {
  316. this._webSocketRoutes.unshift(new network.WebSocketRouteHandler(this._options.baseURL, url, handler));
  317. await this._updateWebSocketInterceptionPatterns({ title: "Route WebSockets" });
  318. }
  319. async _recordIntoHAR(har, page, options = {}) {
  320. const { harId } = await this._channel.harStart({
  321. page: page?._channel,
  322. options: {
  323. zip: har.endsWith(".zip"),
  324. content: options.updateContent ?? "attach",
  325. urlGlob: (0, import_rtti.isString)(options.url) ? options.url : void 0,
  326. urlRegexSource: (0, import_rtti.isRegExp)(options.url) ? options.url.source : void 0,
  327. urlRegexFlags: (0, import_rtti.isRegExp)(options.url) ? options.url.flags : void 0,
  328. mode: options.updateMode ?? "minimal"
  329. }
  330. });
  331. this._harRecorders.set(harId, { path: har, content: options.updateContent ?? "attach" });
  332. }
  333. async routeFromHAR(har, options = {}) {
  334. const localUtils = this._connection.localUtils();
  335. if (!localUtils)
  336. throw new Error("Route from har is not supported in thin clients");
  337. if (options.update) {
  338. await this._recordIntoHAR(har, null, options);
  339. return;
  340. }
  341. const harRouter = await import_harRouter.HarRouter.create(localUtils, har, options.notFound || "abort", { urlMatch: options.url });
  342. this._harRouters.push(harRouter);
  343. await harRouter.addContextRoute(this);
  344. }
  345. _disposeHarRouters() {
  346. this._harRouters.forEach((router) => router.dispose());
  347. this._harRouters = [];
  348. }
  349. async unrouteAll(options) {
  350. await this._unrouteInternal(this._routes, [], options?.behavior);
  351. this._disposeHarRouters();
  352. }
  353. async unroute(url, handler) {
  354. const removed = [];
  355. const remaining = [];
  356. for (const route of this._routes) {
  357. if ((0, import_urlMatch.urlMatchesEqual)(route.url, url) && (!handler || route.handler === handler))
  358. removed.push(route);
  359. else
  360. remaining.push(route);
  361. }
  362. await this._unrouteInternal(removed, remaining, "default");
  363. }
  364. async _unrouteInternal(removed, remaining, behavior) {
  365. this._routes = remaining;
  366. if (behavior && behavior !== "default") {
  367. const promises = removed.map((routeHandler) => routeHandler.stop(behavior));
  368. await Promise.all(promises);
  369. }
  370. await this._updateInterceptionPatterns({ title: "Unroute requests" });
  371. }
  372. async _updateInterceptionPatterns(options) {
  373. const patterns = network.RouteHandler.prepareInterceptionPatterns(this._routes);
  374. await this._wrapApiCall(() => this._channel.setNetworkInterceptionPatterns({ patterns }), options);
  375. }
  376. async _updateWebSocketInterceptionPatterns(options) {
  377. const patterns = network.WebSocketRouteHandler.prepareInterceptionPatterns(this._webSocketRoutes);
  378. await this._wrapApiCall(() => this._channel.setWebSocketInterceptionPatterns({ patterns }), options);
  379. }
  380. _effectiveCloseReason() {
  381. return this._closeReason || this._browser?._closeReason;
  382. }
  383. async waitForEvent(event, optionsOrPredicate = {}) {
  384. return await this._wrapApiCall(async () => {
  385. const timeout = this._timeoutSettings.timeout(typeof optionsOrPredicate === "function" ? {} : optionsOrPredicate);
  386. const predicate = typeof optionsOrPredicate === "function" ? optionsOrPredicate : optionsOrPredicate.predicate;
  387. const waiter = import_waiter.Waiter.createForEvent(this, event);
  388. waiter.rejectOnTimeout(timeout, `Timeout ${timeout}ms exceeded while waiting for event "${event}"`);
  389. if (event !== import_events.Events.BrowserContext.Close)
  390. waiter.rejectOnEvent(this, import_events.Events.BrowserContext.Close, () => new import_errors.TargetClosedError(this._effectiveCloseReason()));
  391. const result = await waiter.waitForEvent(this, event, predicate);
  392. waiter.dispose();
  393. return result;
  394. });
  395. }
  396. async storageState(options = {}) {
  397. const state = await this._channel.storageState({ indexedDB: options.indexedDB });
  398. if (options.path) {
  399. await (0, import_fileUtils.mkdirIfNeeded)(this._platform, options.path);
  400. await this._platform.fs().promises.writeFile(options.path, JSON.stringify(state, void 0, 2), "utf8");
  401. }
  402. return state;
  403. }
  404. backgroundPages() {
  405. return [...this._backgroundPages];
  406. }
  407. serviceWorkers() {
  408. return [...this._serviceWorkers];
  409. }
  410. async newCDPSession(page) {
  411. if (!(page instanceof import_page.Page) && !(page instanceof import_frame.Frame))
  412. throw new Error("page: expected Page or Frame");
  413. const result = await this._channel.newCDPSession(page instanceof import_page.Page ? { page: page._channel } : { frame: page._channel });
  414. return import_cdpSession.CDPSession.from(result.session);
  415. }
  416. _onClose() {
  417. this._closingStatus = "closed";
  418. this._browser?._contexts.delete(this);
  419. this._browser?._browserType._contexts.delete(this);
  420. this._browser?._browserType._playwright.selectors._contextsForSelectors.delete(this);
  421. this._disposeHarRouters();
  422. this.tracing._resetStackCounter();
  423. this.emit(import_events.Events.BrowserContext.Close, this);
  424. }
  425. async [Symbol.asyncDispose]() {
  426. await this.close();
  427. }
  428. async close(options = {}) {
  429. if (this._closingStatus !== "none")
  430. return;
  431. this._closeReason = options.reason;
  432. this._closingStatus = "closing";
  433. await this.request.dispose(options);
  434. await this._instrumentation.runBeforeCloseBrowserContext(this);
  435. await this._wrapApiCall(async () => {
  436. for (const [harId, harParams] of this._harRecorders) {
  437. const har = await this._channel.harExport({ harId });
  438. const artifact = import_artifact.Artifact.from(har.artifact);
  439. const isCompressed = harParams.content === "attach" || harParams.path.endsWith(".zip");
  440. const needCompressed = harParams.path.endsWith(".zip");
  441. if (isCompressed && !needCompressed) {
  442. const localUtils = this._connection.localUtils();
  443. if (!localUtils)
  444. throw new Error("Uncompressed har is not supported in thin clients");
  445. await artifact.saveAs(harParams.path + ".tmp");
  446. await localUtils.harUnzip({ zipFile: harParams.path + ".tmp", harFile: harParams.path });
  447. } else {
  448. await artifact.saveAs(harParams.path);
  449. }
  450. await artifact.delete();
  451. }
  452. }, { internal: true });
  453. await this._channel.close(options);
  454. await this._closedPromise;
  455. }
  456. async _enableRecorder(params, eventSink) {
  457. if (eventSink)
  458. this._onRecorderEventSink = eventSink;
  459. await this._channel.enableRecorder(params);
  460. }
  461. async _disableRecorder() {
  462. this._onRecorderEventSink = void 0;
  463. await this._channel.disableRecorder();
  464. }
  465. }
  466. async function prepareStorageState(platform, storageState) {
  467. if (typeof storageState !== "string")
  468. return storageState;
  469. try {
  470. return JSON.parse(await platform.fs().promises.readFile(storageState, "utf8"));
  471. } catch (e) {
  472. (0, import_stackTrace.rewriteErrorMessage)(e, `Error reading storage state from ${storageState}:
  473. ` + e.message);
  474. throw e;
  475. }
  476. }
  477. async function prepareBrowserContextParams(platform, options) {
  478. if (options.videoSize && !options.videosPath)
  479. throw new Error(`"videoSize" option requires "videosPath" to be specified`);
  480. if (options.extraHTTPHeaders)
  481. network.validateHeaders(options.extraHTTPHeaders);
  482. const contextParams = {
  483. ...options,
  484. viewport: options.viewport === null ? void 0 : options.viewport,
  485. noDefaultViewport: options.viewport === null,
  486. extraHTTPHeaders: options.extraHTTPHeaders ? (0, import_headers.headersObjectToArray)(options.extraHTTPHeaders) : void 0,
  487. storageState: options.storageState ? await prepareStorageState(platform, options.storageState) : void 0,
  488. serviceWorkers: options.serviceWorkers,
  489. colorScheme: options.colorScheme === null ? "no-override" : options.colorScheme,
  490. reducedMotion: options.reducedMotion === null ? "no-override" : options.reducedMotion,
  491. forcedColors: options.forcedColors === null ? "no-override" : options.forcedColors,
  492. contrast: options.contrast === null ? "no-override" : options.contrast,
  493. acceptDownloads: toAcceptDownloadsProtocol(options.acceptDownloads),
  494. clientCertificates: await toClientCertificatesProtocol(platform, options.clientCertificates)
  495. };
  496. if (!contextParams.recordVideo && options.videosPath) {
  497. contextParams.recordVideo = {
  498. dir: options.videosPath,
  499. size: options.videoSize
  500. };
  501. }
  502. if (contextParams.recordVideo && contextParams.recordVideo.dir)
  503. contextParams.recordVideo.dir = platform.path().resolve(contextParams.recordVideo.dir);
  504. return contextParams;
  505. }
  506. function toAcceptDownloadsProtocol(acceptDownloads) {
  507. if (acceptDownloads === void 0)
  508. return void 0;
  509. if (acceptDownloads)
  510. return "accept";
  511. return "deny";
  512. }
  513. async function toClientCertificatesProtocol(platform, certs) {
  514. if (!certs)
  515. return void 0;
  516. const bufferizeContent = async (value, path) => {
  517. if (value)
  518. return value;
  519. if (path)
  520. return await platform.fs().promises.readFile(path);
  521. };
  522. return await Promise.all(certs.map(async (cert) => ({
  523. origin: cert.origin,
  524. cert: await bufferizeContent(cert.cert, cert.certPath),
  525. key: await bufferizeContent(cert.key, cert.keyPath),
  526. pfx: await bufferizeContent(cert.pfx, cert.pfxPath),
  527. passphrase: cert.passphrase
  528. })));
  529. }
  530. // Annotate the CommonJS export names for ESM import in node:
  531. 0 && (module.exports = {
  532. BrowserContext,
  533. prepareBrowserContextParams,
  534. toClientCertificatesProtocol
  535. });