web-dev-qa-db-ja.com

操り人形師|すべてのJavaScriptが実行されるのを待つ

複数のページからスクリーンショットを撮ろうとしていますが、後で比較するために完全にロードする必要があります(遅延ロードしたイメージを含む)。

lazyimages_without_scroll_events.jsの例 が見つかりました。これは非常に役立ちます。

次のコードでは、スクリーンショットは正常に見えますが、いくつかの大きな問題があります。

_async function takeScreenshot(browser, viewport, route) {
  return browser.newPage().then(async (page) => {
    const fileName = `${viewport.directory}/${getFilename(route)}`;

    await page.setViewport({
      width: viewport.width,
      height: 500,
    });
    await page.goto(
        `${config.server.master}${route}.html`,
        {
          waitUntil: 'networkidle0',
        }
    );
    await page.evaluate(() => {
      /* global document,requestAnimationFrame */
      let lastScrollTop = document.scrollingElement.scrollTop;

      // Scroll to bottom of page until we can't scroll anymore.
      const scroll = () => {
        document.scrollingElement.scrollTop += 100;
        if (document.scrollingElement.scrollTop !== lastScrollTop) {
          lastScrollTop = document.scrollingElement.scrollTop;
          requestAnimationFrame(scroll);
        }
      };
      scroll();
    });
    await page.waitFor(5000);
    await page.screenshot({
      path: `screenshots/master/${fileName}.png`,
      fullPage: true,
    });

    await page.close();
    console.log(`Viewport "${viewport.name}", Route "${route}"`);
  });
}
_

Issuepage.waitFor()(タイムアウト)の値が大きくても、ページ上のフロントエンドに関連するJavaScriptのすべてが完全ではない場合がありました実行されました。

JavaScriptがフロントエンドを変更する可能性のある古いページの場合。 F.e.レガシーの場合、_jQuery.matchHeight_。

ベストケース:理想的な世界では、操り人形師はすべてのJavaScriptが評価および実行されるまで待機します。 このようなことは可能ですか?


[〜#〜] edit [〜#〜]
_cody-g_の助けを借りて、スクリプトを少し改善できました。

_function jQueryMatchHeightIsProcessed() {
  return Array.from($('.match-height')).every((element) => {
    return element.style.height !== '';
  });
}

// Within takeScreenshot() after page.waitFor()
await page.waitForFunction(jQueryMatchHeightIsProcessed, {timeout: 0});
_

...しかし、完璧にはほど遠い。ターゲットページで発生するすべてのことを実際に考慮するには、異なるフロントエンドスクリプトに対して同様のソリューションを見つける必要があるようです。

私の場合の_jQuery.matchHeight_の主な問題は、異なる実行で異なる高さを処理することです。画像の遅延読み込みが原因である可能性があります。 Flexboxに交換できるようになるまで待つ必要があるようです。 (^ _ ^)°

修正するその他の問題:

アニメーションを無効にします。

_await page.addStyleTag({
  content: `
    * {
      transition: none !important;
      animation: none !important;
    }
  `,
});
_

スライドショーの処理:

_function handleSwiperSlideshows() {
  Array.from($('.swiper-container')).forEach((element) => {
    if (typeof element.swiper !== 'undefined') {
      if (element.swiper.autoplaying) {
        element.swiper.stopAutoplay();
        element.swiper.slideTo(0);
      }
    }
  });
}

// Within takeScreenshot() after page.waitFor()
await page.evaluate(handleSwiperSlideshows);
_

しかし、まだ十分ではありません。これらのレガシーページを視覚的にテストすることは不可能だと思います。

7
vaxul

次の waitForFunction が役立つ場合があります。これを使用して、任意の関数がtrueと評価されるのを待つことができます。ページのコードにアクセスできる場合は、ウィンドウのステータスを設定し、それを使用して、人形が安全に続行できることを通知するか、他の準備完了状態に依存することができます。 注:この関数はポーリング関数であり、指定可能な間隔で再評価されます。

const watchDog = page.waitForFunction('<your function to evaluate to true>');

例えば。、

const watchDog = page.waitForFunction('window.status === "ready"');
await watchDog;

ページのコードでは、単にwindow.statusからready

複数の非同期ファイルで複数のウォッチドッグを利用するには、次のようなことができます

index.js

...import/require file1.js;
...import/require file2.js;
...code...

file1.js:

var file1Flag=false; // global
...code...
file1Flag=true;

file2.js:

var file2Flag=false; // global
...code...
file2Flag=true;

main.js:

const watchDog = page.waitForFunction('file1Flag && file2Flag');
await watchDog;
7
Cody G