Кукольник | Подождите, пока будет выполнен весь 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.info(`Viewport "${viewport.name}", Route "${route}"`);
  });
}

Проблема: даже при более высоких значениях для page.waitFor() (тайм-аут) иногда не все сценарии Java, связанные с веб-интерфейсом, на страницах выполнялись полностью.

Для некоторых старых страниц, на которых некоторый JavaScript может изменить интерфейс. F.e. в одном из старых случаев - jQuery.matchHeight.

Лучший случай: В идеальном мире Кукловод ждал, пока весь JavaScript не будет оценен и выполнен. Возможно ли что-то подобное?


РЕДАКТИРОВАТЬ
Я мог немного улучшить скрипт с помощью 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);

Но все еще недостаточно. Я считаю, что визуально проверить эти устаревшие страницы невозможно.

Вы когда-нибудь находили универсальный способ добиться этого?

user4487338 04.03.2019 23:24

К сожалению, нет. Все, что я сделал, упоминается в моем РЕДАКТИРОВАТЬ.

vaxul 06.03.2019 08:57
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
15
2
20 478
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Следующий 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;

Да, можно было бы добавить код на целевые страницы. Сложная часть этого решения - найти подходящее место для такого рода функций. Есть несколько скриптов, которые асинхронно загружаются и выполняются с RequireJS. Нет единой конечной точки.

vaxul 26.11.2018 16:37

Правильно. В этом случае вы могли бы создать несколько сторожевых псов, верно? Я не знаю ни одного флага "простоя", который вы могли бы использовать в этом случае.

Cody G 26.11.2018 16:41

Не могли бы вы добавить простой пример кода для целевой страницы, который можно было бы использовать со сторожевым псом?

vaxul 26.11.2018 17:32

Хммм, не знаю, что добавить, но кое-что добавил.

Cody G 26.11.2018 19:42
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(() => {
      scroll(0, 99999)
    });
    await page.waitFor(5000);
    await page.screenshot({
      path: `screenshots/master/${fileName}.png`,
      fullPage: true,
    });

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

Не могли бы вы пояснить, пожалуйста? Пока я вижу, что вы изменили поведение прокрутки. Я не уверен, как это может помочь в моем случае.

vaxul 26.11.2018 17:22

Другие вопросы по теме