Repository: microsoft/playwright
File: packages/playwright-core/src/server/bidi/bidiBrowser.ts (TypeScript)

Code before:
      await (page.delegate as BidiPage).updateHttpCredentials();
  }

  async doAddInitScript(initScript: InitScript) {
    const { script } = await this._browser._browserSession.send('script.addPreloadScript', {
      // TODO: remove function call from the source.
      functionDeclaration: `() => { return ${initScript.source} }`,
      userContexts: [this._userContextId()],
    });
    this._initScriptIds.set(initScript, script);
  }

  async doRemoveInitScripts(initScripts: InitScript[]) {
    const ids: string[] = [];
    for (const script of initScripts) {
      const id = this._initScriptIds.get(script);
      if (id)
        ids.push(id);
      this._initScriptIds.delete(script);
    }
    await Promise.all(ids.map(script => this._browser._browserSession.send('script.removePreloadScript', { script })));
  }

  async doUpdateRequestInterception(): Promise<void> {
    if (this.requestInterceptors.length > 0 && !this._interceptIdPromise) {
      this._interceptIdPromise = this._browser._browserSession.send('network.addIntercept', {
        phases: [bidi.Network.InterceptPhase.BeforeRequestSent],
        urlPatterns: [{ type: 'pattern' }],
      }).then(({ intercept }) => intercept);
    }
    if (this.requestInterceptors.length === 0 && this._interceptIdPromise) {
      const interceptIdPromise = this._interceptIdPromise;
      this._interceptIdPromise = undefined;
      await this._browser._browserSession.send('network.removeIntercept', {
        intercept: await interceptIdPromise
      });
    }
  }

  override async doUpdateDefaultViewport() {
    if (!this._options.viewport)
      return;
    await Promise.all([
      this._browser._browserSession.send('browsingContext.setViewport', {
        viewport: {
          width: this._options.viewport.width,
          height: this._options.viewport.height
        },
        devicePixelRatio: this._options.deviceScaleFactor || 1,
        userContexts: [this._userContextId()],
      }),

Review comment (suggestion):
If you want to handle multiple concurrent calls of route, you can have a separate field `isUpdatingInterception` or something. But in the Playwright API the route/unroute methods are async and the contract is that the user awaits the result before making next call. Concurrent calls are a best effort.

Let's await for the command result and save the intercept id into a field (instead of saving a promise and awaiting it only when it's time to disable interception).  I don't know what ordering guarantees Bidi provides and wether it is safe to send-and-forget here. I'd avoid relying on that and await for the command response before returning from this method.


Code after:
    this._options.httpCredentials = httpCredentials;
    for (const page of this.pages())
      await (page.delegate as BidiPage).updateHttpCredentials();
  }

  async doAddInitScript(initScript: InitScript) {
    const { script } = await this._browser._browserSession.send('script.addPreloadScript', {
      // TODO: remove function call from the source.
      functionDeclaration: `() => { return ${initScript.source} }`,
      userContexts: [this._userContextId()],
    });
    this._initScriptIds.set(initScript, script);
  }

  async doRemoveInitScripts(initScripts: InitScript[]) {
    const ids: string[] = [];
    for (const script of initScripts) {
      const id = this._initScriptIds.get(script);
      if (id)
        ids.push(id);
      this._initScriptIds.delete(script);
    }
    await Promise.all(ids.map(script => this._browser._browserSession.send('script.removePreloadScript', { script })));
  }

  async doUpdateRequestInterception(): Promise<void> {
    if (this.requestInterceptors.length > 0 && !this._interceptId) {
      const { intercept } = await this._browser._browserSession.send('network.addIntercept', {
        phases: [bidi.Network.InterceptPhase.BeforeRequestSent],
        urlPatterns: [{ type: 'pattern' }],
      });
      this._interceptId = intercept;
    }
    if (this.requestInterceptors.length === 0 && this._interceptId) {
      const intercept = this._interceptId;
      this._interceptId = undefined;
      await this._browser._browserSession.send('network.removeIntercept', { intercept });
    }
  }

  override async doUpdateDefaultViewport() {
    if (!this._options.viewport)
      return;
    await Promise.all([
      this._browser._browserSession.send('browsingContext.setViewport', {
        viewport: {
          width: this._options.viewport.width,
          height: this._options.viewport.height
        },
        devicePixelRatio: this._options.deviceScaleFactor || 1,
        userContexts: [this._userContextId()],