Skip to content

GitLab

  • Menu
Projects Groups Snippets
  • Help
    • Help
    • Support
    • Community forum
    • Submit feedback
    • Contribute to GitLab
  • Sign in / Register
  • W web-screenshooter
  • Project information
    • Project information
    • Activity
    • Labels
    • Members
  • Repository
    • Repository
    • Files
    • Commits
    • Branches
    • Tags
    • Contributors
    • Graph
    • Compare
  • Issues 0
    • Issues 0
    • List
    • Boards
    • Service Desk
    • Milestones
  • Merge requests 0
    • Merge requests 0
  • CI/CD
    • CI/CD
    • Pipelines
    • Jobs
    • Schedules
  • Deployments
    • Deployments
    • Environments
    • Releases
  • Packages & Registries
    • Packages & Registries
    • Package Registry
    • Infrastructure Registry
  • Monitor
    • Monitor
    • Incidents
  • Analytics
    • Analytics
    • Value stream
    • CI/CD
    • Repository
  • Wiki
    • Wiki
  • Snippets
    • Snippets
  • Activity
  • Graph
  • Create a new issue
  • Jobs
  • Commits
  • Issue Boards
Collapse sidebar
  • Igor O. Slieptsov
  • web-screenshooter
  • Wiki
  • method

method · Changes

Page history
Basic instructions authored Aug 25, 2021 by Igor O. Slieptsov's avatar Igor O. Slieptsov
Hide whitespace changes
Inline Side-by-side
method.md 0 → 100644
View page @ 903e3ea9
# Метод сбора скриншотов
## Каталогизация скриншотов
Разделяйте скриншоты на разделы и подразделы, создав иерархию.
Ориентируйтесь на структуру сайта и связь функционала страниц.
Офорите её в виде дерева директорий в img.
Именуйте скриншоты в формате `<раздел>/<страница>_<аспект/состояние>`, где
* `<раздел>` — путь к директории относительно img,
* `<страница>` — название страницы или группы страниц, объединённых общей функциональностью и интерфейсом,
* `<аспект/состояние>` — название выделенного объекта на странице, описание состояния, в котором находится система, или описание ситуации, которая демонстрируется скриншотом (может отсутствовать).
Например,
* `admin/login` — страница авторизации (открытая в рамках демонстрации административной компоненты)
* `admin/login_fill` — страница авторизации с заполненными полями данными админской учётной записи
* `admin/login_success` — страница, показанная после успешной авторизации как админа
* `admin/index_auth` — главная страница сайта с выделенной облатью с данными авторизованного администратора
## Скрипты сбора скриншотов
Под скриптом сбора здесь и далее понимается асинхронная функция, которая оперирует одной страницей и собирает скриншоты.
Рассмотрим на примере функции
```javascript
async function loginAsAdmin(page) {
console.log('# login as admin');
await page.goto(domain + '/login.php');
await page.waitForSelector('input');
await takeSS('login_page', page, { boxedElement: '.form-signin' });
await page.type('[name="user"]', params.user);
await page.type('[name="pass"]', params.password);
await page.waitForTimeout(100);
const submitBtn = '.form-signin .btn';
await takeSS('login_fill', page, { hostElement: '.form-signin', boxedElement: submitBtn });
page.on('dialog', async (dialog) => { throw dialog.message(); });
await page.click(submitBtn);
await page.waitForTimeout(1000);
}
```
### Использование скриптов
Добавьте вызов написанного скрипта в функцию `run()`:
```javascript
async function run() {
await startBrowser();
await loginAsAdmin(mainPage); // <-
await takeIndexSS(mainPage);
await stopBrowser();
}
```
Можно объединять несколько скриптов в один составной средствами JavaScript:
```javascript
async takeUserSS() {
await takeUserNewsSS();
await takeUserHelpSS();
// ...
}
```
### Структура скрипта
Начинайте скрипт строкой вида
```javascript
console.log('# login as admin');
```
для того, чтобы видеть прогресс во время работы програмы и контекст при возникновении ошибки.
Следует придерживаться соответствия текстовки названию скрипта.
Старайтесь не создавать новые страницы (`await browser.newPage()`).
Перейдите на требуемую страницу:
```javascript
await page.goto(domain + '/login.php');
```
Старайтесь, если это разумно, в рамках одного скрипта работать с одной страницей.
Типичные действия в скриптах
* переход на страницу;
* заполнение полей;
* активные действия (нажатие на кнопку, симуляция наведения мыши и т.п.);
* снятие скриншотов.
### Управления задержками и ожиданием
После всех действий, которые могут требовать время (загрузка страницы, отработка события и т.п.),
выполняйте задержку, чтобы гарантировать, что страница готова к продолжению работы.
Несмотря на асинхронность всех действий (оператор await),
управление асинхронно возвращается не тогда, когда все последствия действия проявятся, а когда браузер совершил само действие.
Основные методы:
* `await wait(1000)` — задержка на 1с, осуществляемая таймером основной программы;
* `await page.waitForTimeout(1000)` — задержка на 1с, осуществляемая таймером запущенного браузера (ввиду однопоточности JS разница может проявляться);
* `await page.waitForSelector('.form-signin .btn:first-child')` — задержка до появления хотя бы одного элемента, подходящего под указанный селектор;
* `await page.waitForXPath(xpath)` — по-видимому, аналогичен `waitForSelector`;
* `await page.waitForNavigation()` — задержка до наступления определённого события (загрузка DOM, прекращение сетевой активности и т.п.), подробноти в [документации](https://devdocs.io/puppeteer/index#pagewaitfornavigationoptions), где написано, как следует использовать именно этот тип ожидания.
Как правило, характерные времена ожидания небольшие, таким образом, привести любой скрипт в рабочий вид можно, расставив `waitForTimeout` с достаточно большим временем.
Такой подход, однако, не удобен из-за увеличения времени работы всей программы, поэтому по возможности следует отказываться в пользу `waitForSelector` или другого метода.
Методы задержки можно комбинировать.
### Скриншоты
Есть стандартный способ снимать скриншоты — метод `page.screenshot(pathToFile)`.
Можно использовать функцию `takeSS`, определённую в модуль `utils`.
Базовое использование:
```javascript
await takeSS('name', page);
```
Первый аргумент — имя скриншота (см. раздел выше).
Файл сохраняется по пути `img/name.png`.
Имя может содержать слеши, тогда сохранение будет происходить в соответстующую директорию.
Второй аргумент — страница, которой параметризован скрипт.
Дополнительные параметры передаются третьи объектом.
Есть три типичные ситуации:
1. Скриншот отображаемой страницы в соответствии с установленным viewport
```javascript
await takeSS('page', page, { fullPage: false });
```
`fullPage` можно опустить, по умолчанию `false`.
2. Скриншот всей страницы, включая всё содержимое
```javascript
await takeSS('page', page, { fullPage: true });
```
3. Скриншот фрагмента страницы, соответствующему элементу `hostElement`
```javascript
await takeSS('page', page, { hostElement: '.form' });
```
Не известно, конфликтуют `hostElement` с `fullPage` или нет. Рекомендуется придерживаться одного из этих способов использования.
Дополнительные параметры: `boxedElement`, `boxPaddingFrac`, `lineWidthFrac`.
* `boxedElement` — это элемент на странице или внутри `hostElement`, который будет выделен красным прямоугольником.
* `boxPaddingFrac` — отступ между красным прямоугольником и границами элемента (границы определяются браузером, они могут не включать особым образом спозиционированные подэлементы). Указывается в долях от ширины скриншота (т.е. ширины страницы или `hostElement`).
* `lineWidthFrac` — толщина прямоугольника, в долях от ширины скриншота (т.е. ширины страницы или `hostElement`).
`hostElement` и `boxedElement` могут задаваться как Puppeteer-представлениями элементов, например,
```javascript
await await takeSS('page', page, { hostElement: await page.$('.form') });
```
так и строкой-селектором.
Первый способ более гибкий, поскольку им возможно обозначить элемент по признаку, который не выразим селектором CSS, например, (селекторомм XPath)[https://devdocs.io/puppeteer/index#pagexexpression].
#### Примеры
```javascript
await takeSS('login_page', page, { boxedElement: '.form-signin' });
```
Скриншот с именем login\_page, сохраняемый в файл img/login\_page.png, содержит страницу со стандартным размером.
Отображаемая область зависит от предшествующих действия, после загрузки страницы это верхняя часть.
На скриншоте выделен элемент с классом `form-signin`.
```javascript
await takeSS('login_fill', page, { hostElement: '.form-signin', boxedElement: '.form-signin .btn' });
```
Скриншот с именем login\_fill, сохраняемый в файл img/login\_fill.png, содержит элемент страницы с классом `form-signing`, на котором выделен первый дочерний элемент с классом `btn`.
```javascript
await takeSS('admin/index_full', page, { fullPage: true });
```
Скриншот с именем admin/index\_full, сохраняемый в файл admin/index\_full.png.
Скриншот содержит всю страницу целиком, размер определяется содержимым страницы.
## Ввод данных
Заполнение текстовых полей:
```javascript
await page.type('[name="user"]', params.user);
await page.type('[name="pass"]', params.password);
```
В этом примере данные берутся из глобального объекта `params`.
Если скрипт создаёт случайные данные или в ходе работы принимает от сервера новые данные, следует сохранять их в глобальный объект `sideeffects`,
чтобы в будущем иметь возможность ими оперировать.
## Активные действия
Нажатие на кнопку:
```javascript
await page.click('.btn');
```
## Обработка модальных сообщений
Если страница может показать встроенное модальное окно (alert, prompt), следует добавить их обработку.
```javascript
page.on('dialog', async (dialog) => { throw dialog.message(); });
```
Эта команда добавляет обработчик модальных окон, который создаёт исключительную ситуацию, предполагая, что при нормальном взаимодействии модальных окон быть не должно.
Если же модальные окна всё-таки являются частью UI, расширьте функцию дополнительной логикой, например,
```javascript
page.on('dialog', async (dialog) => {
console.log('alert: ' + dialog.message());
if (dialog.message() === "Вопрос сохранён на сервере") {
await dialog.accept();
} else {
throw new Error('Неожиданное сообщение: ' + dialog.message());
}
});
```
Clone repository
  • Home
  • index
  • method
  • run