playwright-coreでFirefox Nightlyを自動操作...できない

playwright-firefox (ブラウザのダウンロード機能付きのやつ) を使った自動操作（ggrks）は、以前に↓の記事を書いた。
https://qiita.com/YusukeIwaki/items/127dba7bb7197ea8d91b

でも、あらかじめFirefoxを詰め込んだDockerコンテナでplaywright自動操作したいときはブラウザダウンロード機能いらないんだけど...？ みたいなことは稀によくあるので、[puppeteer-coreとMacにインストール済みのChromeを使って自動操作](https://qiita.com/YusukeIwaki/items/e8e197ddcdf7f7f3013b) のFirefox版の手順を調べてみた。

## playwright-core + Firefox Nightlyで自動操作を試みる

 playwright-core使ってできる？ と思って調べた。

### ggrksのソース

TypeScriptを書くのが面倒なので、今回はJavaScriptで。

playwright-coreなので、executablePathにFirefox Nightlyのパスを指定しているのがポイント。

```ggrks.js
const playwright = require("playwright-core");

const launchOptions = {
  executablePath: "/Applications/Firefox Nightly.app/Contents/MacOS/firefox",

  // ブラウザ画面を表示しながら（ヘッドレスモードを無効にする）。
  headless: false,

  // 人間味のある速度で入力/操作する。
  slowMo: 50,
};
playwright.firefox.launch(launchOptions).then(async (browser) => {
  // 大抵のサンプルコードはここで単純に browser.newBrowserContext(), browserContext.newPage() しているだけのものが多いが、
  // ブラウザを開いたときにすでに１つタブが開いている場合には、２つ目のタブが開いてしまう。
  // それを防ぐため、すでにタブが開いている場合にはそれを使うようにする。
  let browserContext = await browser.defaultContext();
  let browserPages = await browserContext.pages();
  let page =
    browserPages.length > 0 ? browserPages[0] : await browserContext.newPage();

  await page.goto("https://google.com/");
  await page.click("input[name='q']");
  await page.keyboard.type("playwright");
  await page.keyboard.press("Enter");
});

```

### 動かない。エラーになった。

2020.09.09現在はできない。なんか変な起動パラメータを指定しちゃってるらしく、エラーになる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/74571/8499d199-40b0-6998-0eaf-c59c234fc2c5.png)


### playwrightのソースを読んでみると...

https://github.com/microsoft/playwright/blob/3c69f2a18544e30e2f21786211c23337f9916c4a/src/server/firefox/firefox.ts


```typescript:firefox.ts
    const firefoxArguments = ['-no-remote'];
    if (headless) {
      firefoxArguments.push('-headless');
    } else {
      firefoxArguments.push('-wait-for-browser');
      firefoxArguments.push('-foreground');
    }
    firefoxArguments.push(`-profile`, userDataDir);
    firefoxArguments.push('-juggler', '0');
    firefoxArguments.push(...args);
    if (isPersistent)
      firefoxArguments.push('about:blank');
    else
      firefoxArguments.push('-silent');
    return firefoxArguments;
```

Jugglerっていう、改造版Firefoxみたいなやつ前提のコードっぽくみえる。
Firefox NightlyはChromeと同様に `remote-debugging-port` などを指定しないといけないはず...

おそらくそれが原因で動かないんだろう。


## puppeteer-core + Firefox Nightlyで自動操作を試みる

同様のソースコードをPuppeteerで試してみよう。puppeteerは `product: firefox` 指定をすることでChromeではなくFirefox起動モードになる。

```ggrks.js
const puppeteer = require("puppeteer-core");

const launchOptions = {
  product: "firefox",
  executablePath: "/Applications/Firefox Nightly.app/Contents/MacOS/firefox",

  // ブラウザ画面を表示しながら（ヘッドレスモードを無効にする）。
  headless: false,

  // 人間味のある速度で入力/操作する。
  slowMo: 50,
};
puppeteer.launch(launchOptions).then(async (browser) => {
  // 大抵のサンプルコードはここで単純に browser.newBrowserContext(), browserContext.newPage() しているだけのものが多いが、
  // ブラウザを開いたときにすでに１つタブが開いている場合には、２つ目のタブが開いてしまう。
  // それを防ぐため、すでにタブが開いている場合にはそれを使うようにする。
  let browserPages = await browser.pages();
  let page =
    browserPages.length > 0 ? browserPages[0] : await browser.newPage();

  await page.goto("https://google.com/");
  await page.click("input[name='q']");
  await page.keyboard.type("puppeteer");
  await page.keyboard.press("Enter");
});
```

### puppeteer-coreなら Firefox Nightlyが動いた!

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/74571/ee3f4cf5-a9d6-29c1-1f18-c7695a1b292c.png)

### puppeteerのソースコードを読んでみると...

https://github.com/puppeteer/puppeteer/blob/35cfbe1857aeb7614aa46e0db2732abccccd43d7/src/node/Launcher.ts#L334

```Launcher.ts
    const firefoxArguments = [];
    if (!ignoreDefaultArgs) firefoxArguments.push(...this.defaultArgs(options));
    else if (Array.isArray(ignoreDefaultArgs))
      firefoxArguments.push(
        ...this.defaultArgs(options).filter(
          (arg) => !ignoreDefaultArgs.includes(arg)
        )
      );
    else firefoxArguments.push(...args);

    if (
      !firefoxArguments.some((argument) =>
        argument.startsWith('--remote-debugging-')
      )
    )
      firefoxArguments.push('--remote-debugging-port=0');

    let temporaryUserDataDir = null;

    if (
      !firefoxArguments.includes('-profile') &&
      !firefoxArguments.includes('--profile')
    ) {
      temporaryUserDataDir = await this._createProfile(extraPrefsFirefox);
      firefoxArguments.push('--profile');
      firefoxArguments.push(temporaryUserDataDir);
    }
```

しっかり `remote-debugging-port` を指定している。

## まとめ

2020.09.09現在、インストール済みのFirefoxを使って自動操作するには、playwright-coreではなくpuppeteer-coreの方を使う必要がある。


　

##### 蛇足

実は、[puppeteer-rubyっていうライブラリを個人で開発](https://yusukeiwaki.hatenablog.com/entry/2020/09/08/puppeteer-ruby-0.0.19-firefox-support)していて、 puppeteer-coreにはFirefox Nightlyを自動操作する機能があることは知っていました。
ただ、「Qiitaには、どうせならplaywrightの手順を共有したほうがよいかなー」と思い、調べたところ「playwrightだと動かん！！」ってなったのが、記事執筆の動機でしたｗ