Help us understand the problem. What is going on with this article?

GoogleChromeのDevToolsでブラウザ操作を記録し、Puppeteerのコードを出力してみる

この記事はベリサーブ Advent Calendar 2020 - Qiitaの2日目です。

昨日は@s-tanoueさんのGitHubActionsを用いて、爆速でNuxt.jsのコンポーネントテストをCIで動かす - Qiitaでした。

[12/3 追記]
出力したコードに関連して、ARIAってなんぞ?となった場合はこちらを参照
Puppeteer と ARIA Handler | Medium
[追記おわり]

ChromeのDevToolsにPuppeteerReporderが標準搭載されるらしい

以下の記事をTwitterで見かけました。

Automatically record puppeteer tests - Chrome DevTools - Dev Tips

ChromeのDevToolsのオプションをちょっといじると、Recordingsという項目が追加され、ブラウザ操作をキャプチャしてPuppeteerの実行コードを生成できるとのこと。面白そう。

でもまだ正式リリース前なので、実際動かすまでの手順と動かしてみてどうか、を記録しておきます。

使い方

1. Chrome canary releaseをインストール

Chrome Canary

ここからデベロッパー向けビルドをダウンロードしてインストールします。

image.png

Chrome Canaryをインストールしても既存のChromeは消えず、別のブラウザとしてインストールされますのでご安心を。

2. DevToolsからPuppeteerReporderを有効にする

DevToolsを開いて、歯車のマークを選択

image.png

Experimentsの中の「Recorder」にチェックを入れる

image.png

Reload DevToolsボタンを押す

image.png

Sourcesタブから>>を選んで、Recordingsを選択

image.png

これで記録の準備ができました。

3. 操作を記録する

+Add Recordingを押してはじめます。新しい記録が作成されますので、任意に名前を変えましょう。
下のRecordボタンを押すと記録が始まります。が、このとき注意が必要で、先にテストしたいサイトを開いた状態で開始する必要がありました。

image.png

Recordボタンを押してからURLバーに操作したいサイトのURLを入れても、コード側には反映されず。残念。

Record中の操作は画面下部にリアルタイムに表示されます。

image.png

パスワードは丸見えですね。

未ログイン状態のQiitaのトップで、ユーザ名・メールアドレス・パスワードを入れて登録するボタンを押す操作を記録した結果が以下です。

const puppeteer = require('puppeteer');

(async () => {
    const browser = await puppeteer.launch();
    const page = await browser.newPage();

    await page.goto("https://qiita.com/");
await page.click("aria/qiitan");
await page.click("aria/qiitan");
    await page.click("aria/qiitan");
await page.type("aria/qiitan", "Hoge");
await page.type("aria/qiitan", "Hoge");
    await page.type("aria/qiitan", "Hoge");
await page.type("aria/qiitan@qiita.com", "hoge@hoge.com");
await page.type("aria/qiitan@qiita.com", "hoge@hoge.com");
    await page.type("aria/qiitan@qiita.com", "hoge@hoge.com");
await page.type("aria/********", "hogehoge");
await page.type("aria/********", "hogehoge");
    await page.type("aria/********", "hogehoge");
    await browser.close();
})();

↑が原文ママです。インデントがアレなのと、なぜか1つの操作が3行ずつ表示されてしまっています。

登録するボタンを押す操作が記録されていませんが、規約の同意などのチェックボックスをONにしない状態で登録するボタンを押しても、画面遷移などせずバルーンで警告が出るのみでした。画面遷移など伴わないと記録されない模様。

Puppeteerで動かす

原文ママだと動かせ無さそうだったので、少し調整してみます。

const puppeteer = require('puppeteer');

(async () => {
    const browser = await puppeteer.launch({
        headless: false
    });
    const page = await browser.newPage();

    await page.goto("https://qiita.com/");

    await page.click("aria/qiitan");
    await page.type("aria/qiitan", "Hoge");
    await page.type("aria/qiitan@qiita.com", "hoge@hoge.com");
    await page.type("aria/********", "hogehoge");

    await browser.close();
})();

重複操作を除いたのと、あとはヘッドレスではなく画面表示するようにしました。

これで動かすと・・・

C:\Users\yoshiki.itou\Documents\workspace\my-puppeteer>node index.js
C:\Users\yoshiki.itou\Documents\workspace\my-puppeteer\node_modules\puppeteer\lib\cjs\puppeteer\common\assert.js:26
        throw new Error(message);
              ^

Error: No node found for selector: aria/qiitan
    at Object.exports.assert (C:\Users\yoshiki.itou\Documents\workspace\my-puppeteer\node_modules\puppeteer\lib\cjs\puppeteer\common\assert.js:26:15)
    at DOMWorld.click (C:\Users\yoshiki.itou\Documents\workspace\my-puppeteer\node_modules\puppeteer\lib\cjs\puppeteer\common\DOMWorld.js:276:21)
    at processTicksAndRejections (node:internal/process/task_queues:93:5)
    at async C:\Users\yoshiki.itou\Documents\workspace\my-puppeteer\index.js:11:5

みごとにエラー。ロケータがおかしい?

全てID指定にしてみましょう。

const puppeteer = require('puppeteer');

(async () => {
    const browser = await puppeteer.launch({
        headless: false
    });
    const page = await browser.newPage();

    await page.goto("https://qiita.com/");

    await page.click("#url_name");
    await page.type("#url_name", "Hoge");
    await page.type("#email", "hoge@hoge.com");
    await page.type("#password", "hogehoge");

    await browser.close();
})();

今度はちゃんと動いてくれました。

感想

元記事にあるように、記録すればそのまますぐ使えるというわけではなく、実際には

  • Selectors are appropriate and maintainable.
    • セレクタを適切なもの、メンテしやすいものに変える
  • waits/pauses are added if needed.
    • 待機を入れる
  • Assertions are added in (assuming you're writing a test)
    • アサーションを入れる

などなどの対応が必要になります。このへんはSeleniumIDEをはじめ、画面操作を記録してコードを出力する系のツールには現状共通の課題ですね。

普段別の言語でSelenium使ってる人がJSでPuppeteerやるぞ!となった場合のとっかかりとしてはよさそうです。とりあえず記録して出力されたコードを、エラーの原因調べつつ調整していく、という使い道。

ブラウザの標準機能として備わっていくということで、今後が楽しみです。

YoshikiIto
テスト自動化エヴァンジェリスト、アウトプッター、テストエンジニアのSlackコミュニティTestingCommunityJPオーナー。 Qiitaをはじめネット上での発言は個人のもので、会社や所属団体の見解ではありません。
https://yoshikiito.net/
veriserve
お客様の製品・サービスの品質向上や改善に、検証のプロフェッショナルとして貢献します。
https://www.veriserve.co.jp/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away