Тестирование сайта для всех

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

Это печально, потому что после запуска сайта должна начаться настоящая работа. Разработчики и агентства традиционно боролись с обслуживанием после запуска и обеспечением того, чтобы веб-сайт оставался таким же красивым и оптимизированным, как в первый день его запуска. Когда веб-сайт используется реальными посетителями, клиент делает обновления контента и генерируются данные о трафике, мы должны сосредоточиться на качестве.

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

Агентство Жизнь

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

К счастью, с развитием языков разработки в целом и NodeJS в частности за последние несколько лет даже начинающий разработчик может легко написать простые скрипты для проверки большинства вещей на веб-сайте.

NodeJS — отличный язык для написания быстрых сценариев, использующих существующие библиотеки. То, что может показаться большой проблемой (например, выяснить, есть ли битые изображения на веб-сайте), можно разбить на более мелкие проблемы, используя существующее программное обеспечение.

Настройка NodeJS

Если на вашем локальном компьютере не установлен Node, перейдите в их раздел загрузок и установите его. Пример ниже будет работать с любой версией Node 6+. Для этого руководства вам потребуется некоторое базовое понимание NodeJS, или вы можете посетить учебник для начинающих по NodeJS.

Готовый код

Посмотреть и скачать окончательный код можно на GitHub.

Установка пакета

Если вы проверяете что-то на каждой странице вашего сайта, то вы будете использовать какую-то версию сканера сайта. Webcrawler и Easy Crawler — два хороших варианта с открытым исходным кодом. Мы будем использовать SiteBot для сканирования и Got для проверки изображений.

Начните с установки SiteBot и Got

npm install sitebot got --save

Импортируем библиотеки в наш скрипт

const Crawler = require("sitebot");
const got = require("got");
const fs = require("fs");

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

const crawler = new Crawler({
  url: "http://the-internet.herokuapp.com/broken_images"
});

Определите нашу основную переменную для отслеживания страниц/изображений

const Images = {};

SiteBot — это поисковый робот, управляемый событиями. Есть два события, которые мы будем отслеживать, первое — foundResource.. Оно срабатывает всякий раз, когда сканирование страницы завершено и все ресурсы (изображения, CSS, JS) проанализированы. Мы будем хранить список всех изображений и страниц, на которых они были найдены.

crawler.on("foundResources", function(queueItem, resources) {
  console.log("Finished", queueItem.href);
  Images[queueItem.href] = resources.images;
});

Второе событие, которое мы рассмотрим, — это end, которое происходит после сканирования всего сайта.

На этом этапе наша переменная Images будет содержать список всех страниц сайта и всех изображений на каждой странице. Мы будем использовать эту информацию для проверки статуса каждого изображения.

crawler.on("end", async function() {
  const imageCodes = {};
  const uniqueImages = [];
  for (let url in Images) {
    for (let image of Images[url]) {
      if (!uniqueImages.includes(image)) {
        uniqueImages.push(image);
        try {
          let head = await got.head(image);
          if (!imageCodes[head.statusCode]) imageCodes[head.statusCode] = [];
          imageCodes[head.statusCode].push({ url, image });
        } catch (e) {
          const status = e.code || e.statusCode || e.response.statusCode;
          if (!imageCodes[status]) imageCodes[status] = [];
          imageCodes[status].push({ url, image });
        }
      }
    }
  }
  fs.writeFileSync("./errors.json", JSON.stringify(imageCodes));
});

После того, как мы настроили наши события, мы можем запустить сканер.

crawler.start();

Более глубокое погружение

Давайте разберем событие end немного дальше.

Начнем с установки двух временных переменных. Часто одно и то же изображение (например, логотип) появляется на каждой странице. Вместо того, чтобы тратить время на проверку каждый раз, мы будем хранить общее количество уникальных изображений и проверять только то, является ли оно новым.

const imageCodes = {}; //hold status codes of images
const uniqueImages = []; //hold unique images

Теперь пришло время перебрать нашу основную переменную Images, которую мы устанавливали в событии foundResources. Внешний цикл for проходит через каждую страницу сайта, внутренний цикл for — каждое изображение, найденное на этой странице.

for (let url in Images) {
  for (let image of Images[url]) {
}
}

Проверим уникальность изображения, если оно новое, то добавим его в наш массив uniqueImages.

if (!uniqueImages.includes(image)) {
      uniqueImages.push(image);
}

Теперь мы собираемся использовать библиотеку Got. Это извлекает страницу (и ее коды состояния). Мы используем метод head, так как он быстрее проверяет код состояния (он не загружает тело страницы).

let head = await got.head(image);
if (!imageCodes[head.statusCode]) imageCodes[head.statusCode] = [];
imageCodes[head.statusCode].push({ url, image });

Приведенный выше код извлекает код состояния изображения с сервера. Если этот код состояния еще не был замечен, мы добавляем его в imageCodes. Затем мы помещаем последнее изображение в массив.

Если при выборке произошла ошибка (что может произойти, если домен написан неправильно или возникла какая-либо другая проблема на уровне сети), мы фиксируем ее в блоке кода try/catch.

const status = e.code || e.statusCode || e.response.statusCode;
if (!imageCodes[status]) imageCodes[status] = [];
imageCodes[status].push({ url, image });

Вывод

Конечным результатом является файл JSON, в котором перечислены два поврежденных изображения (404) и страница, на которой они были найдены, а также два изображения, которые были найдены и работают правильно (200).

{
  "200": [
    {
      "url": "http://the-internet.herokuapp.com/broken_images",
      "image": "http://the-internet.herokuapp.com/img/forkme_right_green_007200.png"
    },
    {
      "url": "http://the-internet.herokuapp.com/broken_images",
      "image": "http://the-internet.herokuapp.com/img/avatar-blank.jpg"
    }
  ],
  "404": [
    {
      "url": "http://the-internet.herokuapp.com/broken_images",
      "image": "http://the-internet.herokuapp.com/asdf.jpg"
    },
    {
      "url": "http://the-internet.herokuapp.com/broken_images",
      "image": "http://the-internet.herokuapp.com/hjkl.jpg"
    }
  ]
}

Небольшое замечание: в зависимости от размера веб-сайта и количества изображений на странице этот файл может стать довольно большим.

Резюме

Непрерывное тестирование имеет решающее значение для долгосрочного обслуживания веб-сайта. Запуск собственных тестов не должен быть сложным или дорогим. Используйте NodeJS и готовый сканер веб-сайтов, чтобы начать процесс создания набора тестов.

Если у вас есть вопросы по коду, не стесняйтесь комментировать ниже. Вы также можете подписаться на меня в LinkedIn, Twitter или GitHub.