Кастомные матчеры

В Protractor для проверки результатов тестов чаще всего используются стандартные матчер-функции Jasmine, такие как toEqual, toBe, toContain и другие. Однако сложные проверки, нестандартные сравнения или специфические требования к логике теста требуют создания кастомных матчеров. Кастомные матчеры позволяют расширить возможности Jasmine, делая проверки более выразительными и удобными.


Создание кастомного матчера

Кастомный матчер создаётся через объект с методом expect.extend. Каждое определение матчера должно возвращать объект с двумя обязательными свойствами:

  • pass — логическое значение, указывающее, прошёл ли тест.
  • message — функция или строка с текстом ошибки, которая будет выведена в случае неуспеха.

Пример базового кастомного матчера:

beforeEach(() => {
  jasmine.addMatchers({
    toBeVisible: function() {
      return {
        compare: async function(actual) {
          const isDisplayed = await actual.isDisplayed();
          return {
            pass: isDisplayed,
            message: isDisplayed 
              ? `Ожидалось, что элемент не будет видимым`
              : `Ожидалось, что элемент будет видимым`
          };
        }
      };
    }
  });
});

Здесь создаётся матчер toBeVisible, который проверяет видимость элемента на странице. Ключевой момент — использование async/await, так как взаимодействие с элементами через Protractor всегда асинхронное.


Использование кастомного матчера

После определения матчера его можно использовать в тестах так же, как стандартные матчеры:

it('должен показать элемент', async () => {
  const button = element(by.id('submit'));
  await expectAsync(button).toBeVisible();
});

Обратите внимание на использование expectAsync, которое является обязательным при проверках промисов или ElementFinder в Protractor.


Кастомные матчеры с аргументами

Матчеры могут принимать параметры для более гибкой проверки. Например, проверка текста элемента с учётом регистра:

beforeEach(() => {
  jasmine.addMatchers({
    toHaveTextIgnoringCase: function() {
      return {
        compare: async function(actual, expected) {
          const text = await actual.getText();
          const pass = text.toLowerCase() === expected.toLowerCase();
          return {
            pass: pass,
            message: pass 
              ? `Текст совпадает с ${expected} (игнорируется регистр)`
              : `Ожидалось: ${expected}, но получено: ${text}`
          };
        }
      };
    }
  });
});

Применение:

it('проверка текста элемента без учёта регистра', async () => {
  const label = element(by.css('.label'));
  await expectAsync(label).toHaveTextIgnoringCase('Привет Мир');
});

Обработка сложных сценариев

Кастомные матчеры особенно полезны для:

  • Проверки состояния нескольких элементов одновременно.
  • Проверки асинхронных данных, получаемых с сервера или из локального хранилища.
  • Сравнения сложных объектов, массивов или структур DOM.
  • Валидации, которая выходит за рамки стандартных матчеров Jasmine.

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

beforeEach(() => {
  jasmine.addMatchers({
    allElementsHaveText: function() {
      return {
        compare: async function(elements, expectedText) {
          const texts = await Promise.all(elements.map(el => el.getText()));
          const pass = texts.every(t => t === expectedText);
          return {
            pass: pass,
            message: pass 
              ? `Все элементы содержат текст "${expectedText}"`
              : `Не все элементы содержат текст "${expectedText}": ${texts.join(', ')}`
          };
        }
      };
    }
  });
});

Применение:

it('все элементы списка должны содержать одинаковый текст', async () => {
  const items = element.all(by.css('.item'));
  await expectAsync(items).allElementsHaveText('Готово');
});

Рекомендации по проектированию кастомных матчеров

  1. Ясные сообщения об ошибках Сообщения должны максимально точно отражать, что проверялось и что не прошло. Это ускоряет отладку тестов.

  2. Поддержка асинхронности Все операции с элементами и данными в Protractor возвращают промисы, поэтому матчеры должны быть асинхронными.

  3. Повторное использование Если матчер используется в нескольких тестах, стоит вынести его в отдельный файл и подключать через beforeAll или onPrepare в конфиге Protractor.

  4. Минимизация побочных эффектов Кастомный матчер должен только проверять состояние, но не изменять DOM или данные страницы.


Интеграция с конфигурацией Protractor

Для глобального подключения кастомных матчеров можно использовать файл onPrepare:

// protractor.conf.js
onPrepare: async () => {
  require('./customMatchers');
}

В customMatchers.js определяется весь набор кастомных проверок, что упрощает поддержку и повторное использование в проектах с большим количеством тестов.


Кастомные матчеры в Protractor позволяют писать более выразительные и надежные тесты, упрощают чтение кода и обеспечивают гибкость проверки сложных условий. Они являются неотъемлемой частью масштабируемого тестирования веб-приложений на JavaScript.