puppeteerでSPAのページ表示速度を計測してみた


普段はテスト自動化、ちょっとだけ開発を行なっています。
自動化繋がり(?)で、手動で行なっているページ表示速度の取得を自動化をすることなりました。

やりたいこと

・手動でやっているページ表示速度(ボタンクリック→画面が全て表示されるまで)を定期的に自動で取得したい
・対象はSPA(シングルページアプリケーション)
・リロードの時間も計測したい
・毎日数時間おきに計測して比較したい
・Puppeteer使いたい (Node.jsのライブラリでプログラムからAPIでChromeの操作ができる。詳しくはこちら)

計測方法の検討

Puppeteer + Navigation Timing API

Puppeteer + Navigation Timing API で簡単にできそうと思ったけど、SPAだと計測できなかった(計測できたのは初期表示時だけ。。)

Puppeteer + speedline

手動で計測する場合は、Chrome DevToolsのPerformanceパネルでのパフォーマンス計測を行なっているという情報を得たため、同じようにできないか調査。(左上のRecordボタンで計測できき、左下のような結果が得られる)

Puppeteerを使用することで、Chrome DevToolsのPerformanceパネルでのパフォーマンス計測でexportできるprofileが取れることがわかったため、これを利用することとした

ただし、profileの解析は別でやる必要があるため、別ライブラリ(speedline)を使用することとした

ボタンのクリック後、ページが表示されたタイミングが取れなかったため、
対象画面が表示される直前までマスクがかかっていることを利用し、マスクが外れたタイミング=表示されたとした

具体的な計測方法

 1. Puppeteerで遷移元のページを表示する
 2. recordを開始
 3. ボタンのクリックを行う
 4. マスクが表示されるまで待つ(ボタンクリック後マスクがかかるまでタイムラグがあるため)
 5. マスクが表示されなくなるまで待つ
 6. recordを終了
 7. recoed結果をspeedlineで解析して、結果を取得する

SpeedMeasure.js
const puppeteer = require('puppeteer');
const speedline = require('speedline');
const filename = 'trace.json';

(async () => {

    const browser = await puppeteer.launch({
        devtools: true,
    });

    try {

        let page = (await browser.pages())[0];
        // 1. puppterで遷移元のページを表示する
        await page.goto("http://xxxxxx.com", { timeout: 300000, waitUntil: 'networkidle0' });

        // 2. recordを開始
        await page.tracing.start({ path: filename , screenshots: true});
        // 3. ボタンのクリックを行う
        // 4. マスクが表示されるまで待つ(ボタンクリック後マスクがかかるまでタイムラグがあるため)
        await Promise.all([
            page.waitForXPath("マスクが表示状態時のxpath", 300000),
            (await page.$x("ボタンのxpath"))[0].click()
        ]);
        // 5. マスクが表示されなくなるまで待つ
        await page.waitForXPath("マスクが非表示状態のxpath", 300000);
        // 6. recordを終了
        await page.tracing.stop();

        // 7. 結果をspeedlineで解析して、結果を取得する
        const result = await speedline(filename);
        console.log(result.duration)

    } catch (e) {
        console.error(e);
    } finally {
        browser.close();
    }

})();

最後に

手動と比べたら若干の誤差はありますが、毎日同じ時間に計測し、比較するという目的は満たせているのでよしとしました。
実際にはJenkinsで数時間ごとに実行、結果をスプレットシートに自動で書き込みまでやっています。