Перейти к содержанию

Интеграционное тестирование

Интеграционное тестирование, оно же e2e-тестирование, подразумевает комплексное тестирование модулей через интерфейс приложения.

Применительно к Angular приложению e2e тесты используются для проверки корректности взаимодействия между собой компонентов, которые в совокупности представляют функциональную единицу.

Если unit-тестирование нацелено на проверку атомарных частей кода, например, метода, то интеграционные тесты проверяют взаимодействие этих частей между собой.

Управление e2e тестами и их запуск в браузере осуществляет библиотека Protractor, а сам код написан с использованием Jasmine.

Конфигурационный файл protractor.conf.js находится в директории e2e, а сами файлы тестов — в директории e2e/src.

Запуск тестирования осуществляется командой:

1
ng e2e

Интеграционное тестирование начинается с создания классов Page Object, каждый из которых описывает логику одной конкретной страницы приложения. Например, содержит методы навигации на другие страницы или методы, возвращающие HTML-элементы или значения их свойств.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
export class Page {
    url: string = 'http://localhost:4200';

    getTextByElement(selector) {
        return element(by.css(selector)).getText();
    }

    clickByElement(selector) {
        element(by.css(selector)).click();
    }

    getElement(selector) {
        return element(by.css(selector));
    }
}

Взаимодействие с интерфейсом обеспечивают три основных инструмента библиотеки Protractor:

  • browser — глобальный объект, который предоставляет API команд браузера;
  • element — функция, осуществляющая поиск HTML-элементов в пределах текущей страницы по заданному критерию;
  • by — объект с набором методов, которые возвращают понятный для функции element() критерий поиска;
  • expectedConditions — класс, предоставляющий API для проверки выполнения определенных условий.

Методы browser используются для навигации по приложению, эмуляции событий и т. д. Основные из них:

  • get() — переходит на переданный URL-адрес, выполнение следующего за вызовом метода кода выполняется после завершения перехода, вторым аргументом принимает время в миллисекундах, в течение которого будет ожидаться завершение перехода (по умолчанию 10 секунд);
  • getTitle() — возвращает значение тега <title>
  • getLocationAbsUrl() — возвращает текущий URL-адрес;
  • navigate().forward() — переходит на следующий URL-адрес в истории;
  • navigate().back() — переходит на предыдущий URL-адрес в истории;
  • wait() — приостанавливает процесс тестирования, пока не будет выполнена переданный Promise, вторым параметром можно передать время ожидания в миллисекундах (по умолчанию 30 секунд);
  • actions() — позволяет инициировать пользовательские события в пределах всего браузера (движение курсора или клик мыши, нажатие клавиши и др.). Функции действий:
    • mouseDown() — нажатие и удержание левой кнопки мыши;
    • mouseUp() — отпустить нажатую левую кнопку мыши;
    • mouseMove(element | {x: number, y: number}) — перемещение курсора мыши на элемент или по координатам;
    • doubleClick() — двойное нажатие левой кнопки мыши;
    • dragAndDrop() — событие DragAndDrop.

Пример использования метода actions():

1
2
3
4
5
browser
    .actions()
    .mouseMove({ x: 300, y: 250 })
    .doubleClick()
    .perform();

Здесь курсор мыши сдвигается на 300 пикселей вправо и на 250 пикселей вниз, а затем выполняется двойной клик мыши по месту, соответствующему заданным координатам. Отсчет начинается с левого верхнего угла. Для выполнения действий в конце всегда нужно вызывать метод perform().

Методы объекта by весьма разнообразны. Каждый из них возвращает критерий поиска, который используется для нахождения HTML-элементов функцией element():

  • by.css() — находит элементы по заданному селектору (#id, .class);
  • by.id() — находит элемент по id;
  • by.className() — находит элементы по имени css-класса;
  • by.tagName() — находит элементы по имени HTML-тега;
  • by.input() — возвращает все input-элементы;
  • by.linkText() — находит все ссылки, текстовое значение которых равно переданной строке;
  • by.partialLinkText() — находит все ссылки, в текстовом значение которых содержится переданная строка.

Функция element() по умолчанию возвращает первый найденный элемент, соответствующий заданному критерию поиска. Для нахождения всех элементов используется метод element.all():

1
element.all(by.css('p'));

А получение одного элемента из массива, возвращаемого element.all(), обеспечивает метод get().

1
2
let pEls = element.all(by.css('p'));
let firstP = pEls.get(0);

Для манипуляции отдельным элементом также имеется API.

Получение текстового значения:

1
element(by.id('title')).getText();

Клик по элементу:

1
element(by.buttonText('Submit')).click();

Эмуляция нажатия клавиши, например, в поле формы:

1
2
element(by.input('login')).sendKeys('d');
element(by.input('login')).sendKeys(protractor.Key.TAB);

Сброс значения:

1
element(by.input('login')).clear();

Проверка наличия элемента в DOM-дереве:

1
element(by.tagName('nav')).isPresent();

Проверка видимости элемента:

1
element(by.tagName('sidebar')).isVisible();

Получение габаритных размеров:

1
2
3
4
5
6
element(by.input('login'))
    .getSize()
    .then(function (size) {
        console.log('Width: ' + size.width);
        console.log('Height: ' + size.height);
    });

Теперь рассмотрим подробнее методы класса ExpectedConditions. Абсолютно все методы возвращают объект Promise, поэтому следует их использовать совместно с методом browser.wait().

Проверка кликабельности элемента:

1
2
3
let EC = protractor.expectedConditions;
let btn = element(by.id('confirm'));
browser.wait(EC.elementToBeClickable(btn));

Проверка содержания строки в текстовом значении элемента:

1
2
3
let EC = protractor.expectedConditions;
let btn = element(by.id('confirm'));
browser.wait(EC.textToBePresentInElement(btn, 'Confirm'));

Проверка значения элемента <title> страницы:

1
2
let EC = protractor.expectedConditions;
browser.wait(EC.titleIs('Home'));

Также проверки ожидаемых результатов могут быть скомбинированы оператором or или and:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
let EC = protractor.expectedConditions;
let btn = element(by.id('confirm'));

let textContain = EC.textToBePresentInElement(
    btn,
    'Confirm'
);
let titleCheck = EC.titleIs('Home');

browser.wait(EC.and(textContain, titleCheck));

С полным API можно ознакомиться на официальном сайте Protractor.

Комментарии