Я пытаюсь делать скриншоты с нескольких страниц, которые должны быть полностью загружены (включая ленивые изображения) для последующего сравнения.
Я нашел 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);
Но все еще недостаточно. Я считаю, что визуально проверить эти устаревшие страницы невозможно.
К сожалению, нет. Все, что я сделал, упоминается в моем РЕДАКТИРОВАТЬ.



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Следующий 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. Нет единой конечной точки.
Правильно. В этом случае вы могли бы создать несколько сторожевых псов, верно? Я не знаю ни одного флага "простоя", который вы могли бы использовать в этом случае.
Не могли бы вы добавить простой пример кода для целевой страницы, который можно было бы использовать со сторожевым псом?
Хммм, не знаю, что добавить, но кое-что добавил.
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}"`);
});
}
Не могли бы вы пояснить, пожалуйста? Пока я вижу, что вы изменили поведение прокрутки. Я не уверен, как это может помочь в моем случае.
Вы когда-нибудь находили универсальный способ добиться этого?