web-dev-qa-db-fra.com

Marionnettiste | Attendre que tout JavaScript soit exécuté

J'essaie de prendre des captures d'écran de plusieurs pages, qui devraient être entièrement chargées (y compris les images chargées paresseuses) pour une comparaison ultérieure.

J'ai trouvé le exemple lazyimages_without_scroll_events.js qui aide beaucoup.

Avec le code suivant, les captures d'écran semblent bien, mais il y a un problème majeur.

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}"`);
  });
}

Problème : Même avec des valeurs plus élevées pour page.waitFor() (timeout), parfois tous les JavaScripts liés à l'interface sur les pages n'étaient pas entièrement réalisé.

Pour certaines pages plus anciennes où certains JavaScript pouvaient changer le frontend. F.e. dans un cas hérité, un jQuery.matchHeight.

Meilleur cas : Dans un monde idéal, Marionnettiste attendrait que tout JavaScript soit évalué et exécuté. Est-ce que quelque chose comme ça est possible?


[~ # ~] modifier [~ # ~]
Je pourrais légèrement améliorer le script avec l'aide de 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});

... mais c'est loin d'être parfait. Il semble que je doive trouver des solutions similaires pour différents scripts frontaux pour vraiment prendre en compte tout ce qui se passe sur la page cible.

Le principal problème avec jQuery.matchHeight Dans mon cas est qu'il traite différentes hauteurs dans différentes séries. Peut-être causé par le chargement d'images par lazyl. Il semble que je doive attendre de pouvoir le remplacer par Flexbox. (^ _ ^) °

Autres problèmes à résoudre:

Désactiver les animations:

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

Gérer les diaporamas:

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);

Mais pas encore assez. Je pense qu'il est impossible de tester visuellement ces pages héritées.

7
vaxul

Ce qui suit waitForFunction peut vous être utile, vous pouvez l'utiliser pour attendre que n'importe quelle fonction arbitraire soit évaluée à true. Si vous avez accès au code de la page, vous pouvez définir l'état de la fenêtre et l'utiliser pour informer le marionnettiste qu'il est sûr de continuer, ou simplement compter sur une sorte d'autre état prêt. Remarque: cette fonction est une fonction d'interrogation, et réévalue à un certain intervalle qui peut être spécifié.

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

Par exemple.,

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

Dans le code de votre page, il vous suffit de définir le window.status à ready

Pour utiliser plusieurs chiens de garde dans plusieurs fichiers asynchrones, vous pouvez faire quelque chose comme

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