埋点は、B 站の HTML5 プレーヤーの開発とテストプロセスでの痛みの一つです。埋点の種類とインターフェースパラメータが多く、テストは面倒でエラーが発生しやすいです。
テストは面倒ですが、ルールは非常にシンプルです。たとえば、ボタンをクリックしたり、ホバーしたり、エラーを報告したり、再生やパフォーマンスを報告したりすることです。では、これらの面倒で機械的でエラーが発生しやすいテスト作業を自動化の E2E テストで代替することはできるでしょうか?
埋点のオンライン事故の後、私は 1 日かけていくつかの探索を行い、最終的にはかなりうまくいきました。ここでは、簡単なまとめをします。
テストスクリプトの作成#
ユーザー操作をシミュレートするには、ヘッドレスブラウザが必要です。私は Jest + Puppeteer の組み合わせを使用しました。
Jest はテストフレームワークであり、Puppeteer は Chrome または Chromium を制御するために使用されます。
Jest を選んだのは、私が Jest に最も精通しているからです。そして、jest-puppeteerというプリセットを見つけました。必須ではありませんが、Puppeteer の操作を簡素化することができます。
依存関係をインストールします:
npm install --save-dev jest jest-puppeteer puppeteer
テストスクリプトは非常にシンプルです:
describe('log', () => {
beforeAll(async () => {
page.goto('https://www.bilibili.com/video/av44890855');
});
it('play_screen', async (done) => {
page.on('request', (request) => {
if (request.url().match(/^https:\/\/data\.bilibili\.com\/log\/web\?play_screen...パラメータパラメータ/)) {
done();
}
});
page.click('video');
});
});
HeadlessChrome に再生ページを開かせ、ページのリクエストインターフェースを監視し、video 要素をクリックすることで play_screen の埋め込みがブラウザにリクエストされたことを監視し、テストが成功したことを確認します。
問題はなさそうですが、テストを実行してみると失敗しました。
何が起こったのでしょうか?headless: false
の設定をしてテストのプロセスを見てみました。
HTML5 プレーヤーがサポートされていないため、Flash プレーヤーがロードされたことが原因でした。
Puppeteer のドキュメントによると
Puppeteer は Chromium にバンドルされています - Chrome ではありません...Puppeteer は AAC や H.264 などのライセンスされた形式をサポートしていません
解決策も非常に簡単で、Puppeteer に付属している Chromium をローカルの Chrome に置き換えるだけです。
launch: {
executablePath: '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome'
}
テストが成功しました。
Chrome をサービスとして使用する#
先ほどはローカルの Chrome を使用しましたが、これはローカル環境に依存していますし、自動化テストとしてテストマシンで実行することもできません。
そのため、テストマシンでdocker コンテナを実行しました。これにより、Chrome をサービスとして使用できるようになりました。テストスクリプトは、websocket プロトコルを使用して docker 内の Chrome を操作します。これにより、ローカルの Chrome に依存しないようになります。
コンテナを起動します:
docker pull browserless/chrome:release-chrome-stable
docker run -d -p 3000:3000 browserless/chrome:release-chrome-stable
使用方法:
connect: {
browserWSEndpoint: 'ws://localhost:3000'
}
JavaScript のハイジャック#
これにより、オンラインバージョンが使用され、ローカルのコードがテストされません!
ああ、言い忘れましたが、オンラインの JavaScript をローカルバージョンにハイジャックする必要があります。
await page.setRequestInterception(true);
page.goto('https://www.bilibili.com/video/av44890855');
page.on('request', (request) => {
if (request.url().match(/player\.js/)) {
request.respond({
status: 200,
contentType: 'application/javascript',
body: fs.readFileSync('dist/release/player.js').toString()
});
} else {
request.continue();
}
});