#30 Тестируем фабрики в AngularJS

poster
В этом уроке мы напишем тесты для фабрики с помощью angular-mocks и karma runner.
Понравилось? Поделитесь с друзьями!
Понравилось?
Поделитесь с друзьями!
Комментарии
Текст видео

Всем привет. В этом уроке мы с вами разберем, как тестировать фабрики в AngularJS. Для рана тестов я предпочитаю использовать karma runner. Для начала, его нужно установить глобально с помощью команды

npm install -g karma-cli

Это поставит пакет karma-cli глобально. Теперь нам нужно сгенерировать файл конфигурации. Для этого напишем

karma init karma.conf.js

Это запустит процесс создания файла. Нам нужно ответить на ряд вопросов.

  1. Мы будем использовать jasmine
  2. requireJS нам не нужен
  3. использовать мы будем Chrome
  4. как исходные файлы мы будем использовать js/*.js.
  5. как файлы текста мы будем использовать test/**/*Spec.js
  6. не эксклудим никакие файлы
  7. да мы хотим, чтобы карма вотчила все изменения

Теперь, как мы видим у нас появился файл karma.conf. Так указаны все данные, которые мы ввели.

Теперь давайте создадим папку js и в ней файл main.js

var app = angular.module('app', []);

app.factory('playlist', function () {
  var tracks = [
    {
      id: 1,
      name: 'Track 01'
    },
    {
      id: 2,
      name: 'Track 02'
    }
  ];
  return {
    name: 'Metallica',
    getTracks: function () {
      return tracks;
    }
  }
});

Мы создали наш app без зависимостей. Описали фабрику playlist, которая содержит name и метод, getTracks, который возвращает список треков. Трека у нас статический.

Теперь создадим папку test и в ней файл mailSpec.js. Помните, что наш паттерн для поиска файлов *.Spec, поэтому, если мы не напишем Spec в названии, то файл оно не найдет.

Если вы работали раньше с jasmine, вы должны знать такие слова как describe и it. Describe нам необходим для того, чтобы несколько тестов обьединять в один блок, а it нам нужен для конкретного теста.

describe('playlist', function () {
  it('!!', function () {

  });
});

Это будет наш главный блок describe, в котором у нас будут идти тесты.

Теперь давайте инициализируем наш app и заинджектим в него factory. Для этого нам поможет beforeEach. Это специальная функция, которая выполняется перед каждым тестом

describe('playlist', function () {
  va playlist;
  beforeEach(function () {
      module('app');
      inject(function (_playlist_) {
        playlist = _playlist_;
      });
  });

  it('!!', function () {

  });
});

module('app') - это модуль, который будет инициализирован. Inject же, помогает нам заинджектить фабрику в наш playlist. Для того, чтобы он нам был доступен в всех тестах инджектим его вот таким образом. Переменная playlist нам доступна в всех тестах.

Теперь давайте напишем

it('!!', function () {
  expect(2).toEqual(1);
});

Запустим наши тесты

karma start

Вот стартанул браузер и пишет

angular is not defined

Это логично, поскольку angular мы не добавили в karma.conf. У меня есть папка vendor и в ней лежать 2 файла - angular.js и angular-mocks.js. Давайте подключим их в раздел files в конфиг кармы. Первым нужно подключать angular, так как без него не будет работать angular-mocks.

files: [
  'vendor/angular.js',
  'vendor/angular-mocks.js'
]

Зачем нам angular-mocks? Он помогает нам использовать такие функции, как module, inject, которые нам здесь доступны.

Давайте запустим karma start еще раз. Как мы видим, тесты у нас запустились и у нас есть ошибка, так как 2 не равняется 1.

Теперь давайте напишем тест, который будет проверять, что у фабрики сейчас корректное имя.

it('should get correct playlist name', function () {
  expect(playlist.name).toEqual('111');
});

Сначала сделаем, чтобы наш тест упал. Как мы видим, у нас видит вотчер. Это вотчер кармы, и все тесты сразу же перезапускаются.

Expected 'Metallica' to equal '111'

Это как раз нам и показывает, что у нас отлично заинджектился playlist в наш app. Давайте исправим тест, чтобы он прошел.

it('should get correct playlist name', function () {
  expect(playlist.name).toEqual('Metallica');
});

И мы видим, что наш тест прошел.

Теперь точно так же мы можем протестить, что функция getTracks возвращает нам правильный список треков.

it('should get list of tracks', function () {
  expect(playlist.getTracks()).toEqual(222);
})

Как мы видим, теперь у нас тест падает.

Давайте скопируем массив и сделаем, чтобы тест прошел.

it('should get list of tracks', function () {
  var tracks = [
    {
      id: 1,
      name: 'Track 01'
    },
    {
      id: 2,
      name: 'Track 02'
    }
  ];
  expect(playlist.getTracks()).toEqual(tracks);
})

Теперь у нас есть 2 успешных теста. Теперь если нам потом захочется поменять что-то в код, например имя в фабрике, то мы сразу же видим, что наши тесты валятся и не проходят.

Как мы видим, karma проверяет все наши изменения при сохранении. Тестировать фабрики в angular достаточно просто, мы карму дольше настраивали, чем тесты писали. Karma, сама по себе, позволяет ранить любые тесты, хоть для директив, хоть для контроллеров.

В следующем уроке мы разберем как мокать зависимости для того, чтобы тестировать ее изолировано.

Только зарегистрированные пользователи могут оставлять комментарии.  Войдите, пожалуйста.
vlad
2 лет назад
вечер добрый. каким образом в Trello можно реализовать автозагрузку через N секунд. если ответите в течение нескольких часов буду благодарен
monsterlessons
2 лет назад
Я бы с удовольствием ответил, но мне абсолютно не понятно, что такое автозагрузка.
vlad
2 лет назад
снова страницу перезагрузить. например открыта страница, а в cards добавилась новая карта. каким образом можно отобразить новую карту если не location.replace(index.html) - в этом случае - перезагружает, но перезагружает как и в ручную если нажать обновить. мне же нужно что бы через каждые N секунд - страница обновлялась - и тогда в этом случае новая карта отобразиться
monsterlessons
2 лет назад
В серии про Trello все карты отображались сразу же после добавления. Мне кажется, что вы идете каким-то сильно неправильным путем. В javascript в том и плюс, что абсолютно все можно перерисовать на странице на обновляя ее. Если же вам все таки это надо setInterval(() => { location.reload() }, 5000)
vlad
2 лет назад
При location.reload() происходит тоже самое что и при location.replace(index.html) - страница перезагружается, как при ручном обновление - ВСЕ ПЕРЕЗАГРУЖАЕТСЯ. я же хочу сделать чтобы перезагрузились только карточки. я реализовал - что когда при фильтрации по заказчику карточки перезагружаются и отображаются только его карточки. перезагружаются ТОЛЬКО карточки - добился этого когда повесил это событие на переменную в контроле и ng-if переменная в html. но вот что бы происходило автообновление через каждые n сек - не получается. https://github.com/vlad-74/SimbirSoft
vlad
2 лет назад
например - git = 9 уроков. без разницы как заходить - через Категории или через Серии. Клик на просмотр. Видео проигрывается. Видео завершается - ВСЕ КИНО ЗАКОНЧИЛОСЬ. для просмотра следующего урока нужно на Категории - выйти и нажать на новый урок, на Серии почти аналогично - пройти вниз и нажать следующий урок. Т.е. под экраном нет кнопок - следующий и предыдущий урок или как на youtube где есть функционал - воспроизвести все. поэтому большинство уроков просмотрел на youtube - удобно. это так пожелание. За то что Вы реализовали на сайте - большой респект и уважуха :)
monsterlessons
2 лет назад
Спасибо за фидбек. Внутри серий предыдущий/следующий обязательно реализую. Это уже есть в планах.
vlad
2 лет назад
рад что чем то помог в ответ. еще раз - то что Вы делаете это очень большая помощь начинающим осваивать js
vlad
2 лет назад
Замечание небольшое - не очень удобно когда нет возможности просматривать тему "насквозь". Всегда приходиться возвращаться в корневую позицию или смотреть тему на youtube если она есть.
monsterlessons
2 лет назад
Всмысле? Что вы имеете ввиду?