Russian (Pусский) translation by Ilya Nikov (you can also view the original English article)

Test Driven Development - это практика программирования, которую проповедовали и продвигали все сообщества разработчиков на планете. И все же это рутина, которая в значительной степени игнорируется разработчиком при изучении нового фреймворка. Написание модульных тестов с самого начала проекта поможет вам лучше писать код, выявлять ошибки и поддерживать более эффективный рабочий процесс разработки.
Разработка с использованием тестов в Angular
Angular является полно-функциональной платформой для фронт-енд разработки и имеет собственный набор инструментов для тестирования. В этом учебнике мы будем использовать следующие инструменты:
- Jasmine Framework. Jasmine - популярный фреймворк для тестирования JavaScript. С Jasmine вы можете написать тесты, которые будут более выразительны и понятны. Вот пример для начала.
it('should have a defined component', () => { expect(component).toBeDefined(); });
- Karma Test Runner. Karma - это инструмент, который позволяет тестировать ваше приложение в нескольких браузерах. У Karma есть плагины для браузеров, таких как Chrome, Firefox, Safari и многих других. Но я для тестирования предпочитаю использовать headless браузер. В headless браузере отсутствует графический интерфейс, и таким образом вы можете сохранить результаты теста внутри своего терминала. В этом уроке мы настроим Karma для работы с Chrome и, а также дополнительно с headless версией Chrome.
- Angular Testing Utilities. Утилиты тестирования Angular предоставляют вам библиотеку для создания тестовой среды для вашего приложения. Классы, такие как
TestBed
иComponentFixtures
, и вспомогательные функции, такие какasync
иfakeAsync
, являются частью пакета@angular/core/testing
. Знакомство с этими утилитами необходимо, если вы хотите написать тесты, которые показывают, как ваши компоненты взаимодействуют со своими собственными шаблонами, сервисами и другими компонентами.
В этом уроке мы не собираемся описывать функциональные тесты с помощью Protractor. Protractor - популярный сквозной тестовый фреймворк, который взаимодействует с пользовательским интерфейсом приложения, используя фактический браузер.
В этом уроке мы больше озабочены тестированием компонентов и их логики. Тем не менее, мы напишем пару тестов, которые демонстрируют базовое взаимодействие с пользовательским интерфейсом, используя фреймворк Jasmine.
Наша цель
Цель этого учебника - создать интерфейс для приложения Pastebin в тестовой среде разработки. В этом уроке мы будем следовать популярной мантре TDD: «красный/зеленый/рефакторинг». Мы будем писать тесты, которые первоначально не выполняются (красные), а затем мы работаем над нашим кодом, чтобы они проходили (зеленые). Мы так же будем рефакторить наш код, когда он начнет вонять, что означает, что он раздувается и становится уродлив.
Мы будем писать тесты для компонентов, их шаблонов, сервисов и класса Pastebin. Изображение ниже иллюстрирует структуру нашего приложения Pastebin. Элементы, которые выделены серым цветом, будут рассмотрены во второй части учебника.

В первой части серии мы сосредоточимся только на создании тестовой среды и написании базовых тестов для компонентов. Angular является фреймворком, основанным на компонентах; поэтому необходимо потратить некоторое время, чтобы познакомиться с написанием тестов для компонентов. Во второй части серии мы напишем более сложные тесты для компонентов, компонентов с входными данными, маршрутизируемыми компонентами и службами. К концу серии у нас будет полностью функционирующее приложение Pastebin, которое будет выглядеть так.



В этом уроке вы узнаете, как:
- настроить Jasmine и Karma
- создать класс Pastebin
- создать каркас для PastebinService
- создать два компонента, Pastebin и AddPaste
- написать единичные тесты
Весь код для учебника доступен на Github.
https://github.com/blizzerand/pastebin-angular
Клонируйте репозиторий и не стесняйтесь проверить код, если у вас возникнут сомнения на любом этапе этого урока. Давайте начнем!
Настройка Jasmine и Karma
Разработчики в Angular упростили создание нашей тестовой среды. Для начала нам нужно сначала установить Angular. Я предпочитаю использовать Angular-CLI. Это решение «все-в-одном», которое заботится о создании, генерации, сборке и тестировании вашего Angular проекта.
ng new Pastebin
Вот структура каталогов, созданная Angular-CLI.
Поскольку нас больше интересует тестирование в Angular, нам нужно найти два типа файлов.
karma.conf.js - это файл конфигурации для тестировщика Karma и единственный файл конфигурации, который нам понадобится для написания модульных тестов в Angular. По умолчанию в качестве браузера для Karma используется Chrome. Мы создадим свой собственный ланчер для запуска headless Chrome и добавим его в массив browsers
.
/*karma.conf.js*/ browsers: ['Chrome','ChromeNoSandboxHeadless'], customLaunchers: { ChromeNoSandboxHeadless: { base: 'Chrome', flags: [ '--no-sandbox', // See https://chromium.googlesource.com/chromium/src/+/lkgr/headless/README.md '--headless', '--disable-gpu', // Without a remote debugging port, Google Chrome exits immediately. ' --remote-debugging-port=9222', ], }, },
Другим типом файла, который нужно найти, является все, что заканчивается на .spec.ts
. По соглашению тесты, написанные на Jasime, называются спецификациями. Все тестовые спецификации должны быть расположены внутри каталога приложения src/app/
, поскольку именно здесь Karma ищет тестовые спецификации. Если вы создаете новый компонент или службу, важно, чтобы вы размещали ваши тестовые спецификации в том же каталоге, в котором находится код компонента или службы.
Команда ng new
создала файл app.component.spec.ts
для нашего app.component.ts
. Откройте его и хорошенько рассмотрите тесты Jasmine в Angular. Даже если этот код для вас не имеет никакого смысла, это нормально. Мы сохраним AppComponent так, как он выглядит сейчас, и используем его для размещения маршрутов далее в учебнике.
Создание класса Pastebin
Нам нужен класс Pastebin для моделирования нашего Pastebin внутри компонентов и тестов. Вы можете создать его с помощью Angular-CLI.
ng generate class Pastebin
Добавьте в Pastebin.ts следующую логику:
export class Pastebin { id: number; title: string; language: string; paste: string; constructor(values: Object = {}) { Object.assign(this, values); } } export const Languages = ["Ruby","Java", "JavaScript", "C", "Cpp"];
Мы определили класс Pastebin, и каждый экземпляр этого класса будет иметь следующие свойства:
-
id
title
language
paste
Создайте еще один файл с именем pastebin.spec.ts
для набора тестов.
/* pastebin.spec.ts */ //import the Pastebin class import { Pastebin } from './pastebin'; describe('Pastebin', () => { it('should create an instance of Pastebin',() => { expect(new Pastebin()).toBeTruthy(); }); })
Набор тестов начинается с блока describe
, который является глобальной функцией Jasmine, которая принимает два параметра. Первый параметр - это название набора тестов, а второй - его фактическая реализация. Спецификации определяются с использованием функции it
, которая принимает два параметра, аналогичные параметрам блока describe
.
Множество спецификаций (блоков it
) можно вставить внутри набора тестов (блок describe
). Тем не менее, убедитесь, что имена тестовых наборов названы так, что они недвусмысленны и читаемы, потому что они предназначены для использования в качестве документации для читателя.
Ожидания, реализованные с использованием функции expect
, используются Jasmine для определения того, должна ли спецификация проходить или терпеть неудачу. Функция expect
принимает параметр, который известен как фактическое значение. Затем он соединен цепью с другой функцией, которая принимает ожидаемое значение. Эти функции называются вспомогательными функциями, и в этом учебнике мы будем использовать функции матчинга, такие как toBeTruthy()
, toBeDefined()
, toBe()
и toContain()
.
expect(new Pastebin()).toBeTruthy();
Таким образом, с помощью этого кода мы создали новый экземпляр класса Pastebin и ожидаем, что это будет правдой. Давайте добавим еще одну спецификацию, чтобы подтвердить, что модель Pastebin работает так как нужно.
it('should accept values', () => { let pastebin = new Pastebin(); pastebin = { id: 111, title: "Hello world", language: "Ruby", paste: 'print "Hello"', } expect(pastebin.id).toEqual(111); expect(pastebin.language).toEqual("Ruby"); expect(pastebin.paste).toEqual('print "Hello"'); });
Мы создали экземпляр класса Pastebin и добавили несколько ожиданий в нашу тестовую спецификацию. Запустите ng test
, чтобы проверить, что все тесты зеленые.
Создание каркаса для службы
Создайте службу, используя следующую команду.
ng generate service pastebin
В PastebinService
будет установлена логика отправки HTTP-запросов на сервер; однако у нас нет API-интерфейса сервера для создаваемого нами приложения. Поэтому мы собираемся моделировать связь с сервером с помощью модуля, известного как InMemoryWebApiModule.
Настройка Angular-in-Memory-Web-API
Установите angular-in-memory-web-api
через npm:
npm install angular-in-memory-web-api --save
Обновите AppModule до этой версии.
/* app.module.ts */ import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; //Components import { AppComponent } from './app.component'; //Service for Pastebin import { PastebinService } from "./pastebin.service"; //Modules used in this tutorial import { HttpModule } from '@angular/http'; //In memory Web api to simulate an http server import { InMemoryWebApiModule } from 'angular-in-memory-web-api'; import { InMemoryDataService } from './in-memory-data.service'; @NgModule({ declarations: [ AppComponent, ], imports: [ BrowserModule, HttpModule, InMemoryWebApiModule.forRoot(InMemoryDataService), ], providers: [PastebinService], bootstrap: [AppComponent] }) export class AppModule { }
Создайте InMemoryDataService
, который реализует InMemoryDbService
.
/*in-memory-data.service.ts*/ import { InMemoryDbService } from 'angular-in-memory-web-api'; import { Pastebin } from './pastebin'; export class InMemoryDataService implements InMemoryDbService { createDb() { const pastebin:Pastebin[] = [ { id: 0, title: "Hello world Ruby", language: "Ruby", paste: 'puts "Hello World"' }, {id: 1, title: "Hello world C", language: "C", paste: 'printf("Hello world");'}, {id: 2, title: "Hello world CPP", language: "C++", paste: 'cout<<"Hello world";'}, {id: 3, title: "Hello world Javascript", language: "JavaScript", paste: 'console.log("Hello world")'} ]; return {pastebin}; } }
Здесь pastebin
представляет собой массив выборочных паст, которые будут возвращены или обновлены при выполнении действия HTTP, например http.get
или http.post
.
/*pastebin.service.ts */ import { Injectable } from '@angular/core'; import { Pastebin } from './pastebin'; import { Http, Headers } from '@angular/http'; import 'rxjs/add/operator/toPromise'; @Injectable() export class PastebinService { // The project uses InMemoryWebApi to handle the Server API. // Here "api/pastebin" simulates a Server API url private pastebinUrl = "api/pastebin"; private headers = new Headers({'Content-Type': "application/json"}); constructor(private https: Http) { } // getPastebin() performs http.get() and returns a promise public getPastebin():Promise<any> { return this.http.get(this.pastebinUrl) .toPromise() .then(response => response.json().data) .catch(this.handleError); } private handleError(error: any): Promise<any> { console.error('An error occurred', error); return Promise.reject(error.message || error); } }
Метод getPastebin()
выполняет запрос HTTP.get и возвращает обещание, которое разрешается в массив объектов Pastebin, возвращаемых сервером.
Если при запуске спецификации вы получаете сообщение No provider for HTTP error, то вам необходимо импортировать HTTPModule в соответствующий файл spec.
Начало работы с компонентами
Компоненты - это самый базовый строительный блок пользовательского интерфейса в приложении Agnular. Angular приложение представляет собой дерево компонентов.
- Angular документация
Как было отмечено ранее в разделе «Обзор», мы будем работать над двумя компонентами в этом уроке: PastebinComponent и AddPasteComponent. Компонент Pastebin состоит из таблицы, в которой перечислены все вставки, полученные с сервера. Компонент AddPaste содержит логику создания новых паст.
Проектирование и тестирование компонента Pastebin
Идем дальше и создаем компоненты с помощью Angular-CLI.
ng g component --spec=false Pastebin
Параметр --spec = false
указывает Angular CLI не создавать спецификационный файл. Это связано с тем, что мы хотим писать модульные тесты для компонентов с нуля. Создайте файл pastebin.component.spec.ts
внутри папки pastebin-component.
Вот код для pastebin.component.spec.ts.
import { TestBed, ComponentFixture, async } from '@angular/core/testing'; import { DebugElement } from '@angular/core'; import { PastebinComponent } from './pastebin.component'; import { By } from '@angular/platform-browser'; import { Pastebin, Languages } from '../pastebin'; //Modules used for testing import { HttpModule } from '@angular/http'; describe('PastebinComponent', () => { //Typescript declarations. let comp: PastebinComponent; let fixture: ComponentFixture<PastebinComponent>; let de: DebugElement; let element: HTMLElement; let mockPaste: Pastebin[]; // beforeEach is called once before every `it` block in a test. // Use this to configure to the component, inject services etc. beforeEach(()=> { TestBed.configureTestingModule({ declarations: [ PastebinComponent ], // declare the test component imports: [ HttpModule], }); fixture = TestBed.createComponent(PastebinComponent); comp = fixture.componentInstance; de = fixture.debugElement.query(By.css('.pastebin')); element = de.nativeElement; }); })
Здесь многое происходит. Давайте разложим его и рассмотрим по блокам. Внутри блока describe
мы объявили некоторые переменные, а затем мы использовали функцию beforeEach
. beforeEach()
является глобальной функцией, предоставляемой Jasmine, и, как следует из названия, она вызывается один раз перед каждой спецификацией в блоке describe
, в котором она вызывается.
TestBed.configureTestingModule({ declarations: [ PastebinComponent ], // declare the test component imports: [ HttpModule], });
Класс TestBed
является частью утилит тестирования Angular, и он создает модуль тестирования, аналогичный модулю @NgModul
e. Кроме того, вы можете настроить TestBed
с помощью метода configureTestingModule
. Например, вы можете создать тестовую среду для своего проекта, которая эмулирует фактическое приложение Angular, и затем вы можете вытащить компонент из вашего прикладного модуля и снова присоединить его к этому тестовому модулю.
fixture = TestBed.createComponent(PastebinComponent); comp = fixture.componentInstance; de = fixture.debugElement.query(By.css('div')); element = de.nativeElement;
Из документации Angular:
МетодcreateComponent
возвращает компонентComponentFixture
, дескриптор тестовой среды, окружающей созданный компонент. Фикстура обеспечивает доступ к самому экземпляру компонента и кDebugElement
, который является дескриптором элемента DOM компонента.
Как уже упоминалось выше, мы создали фикстуру PastebinComponent
, а затем использовали эту фикстуру для создания экземпляра компонента. Теперь мы можем получить доступ к свойствам и методам компонента внутри наших тестов, вызвав имя comp.property_name
. Поскольку фикстура также обеспечивает доступ к debugElement
, мы теперь можем запросить элементы DOM и селектора.
В нашем коде есть проблема, о которой мы еще не подумали. Наш компонент имеет внешний шаблон и файл CSS. Извлечение и чтение их из файловой системы - это асинхронная активность, в отличие от остальной части кода, которая является синхронной.
Angular предлагает вам функцию async()
, которая заботится обо всех асинхронных вещах. async занимается тем, что отслеживает все асинхронные задачи внутри него, скрывая от нас сложность асинхронного выполнения. Итак, теперь у нас будет две функции beforeEach, асинхронная beforeEach()
и синхронная beforeEach()
.
/* pastebin.component.spec.ts */ // beforeEach is called once before every `it` block in a test. // Use this to configure to the component, inject services etc. beforeEach(async(() => { //async before is used for compiling external templates which is any async activity TestBed.configureTestingModule({ declarations: [ PastebinComponent ], // declare the test component imports: [ HttpModule], }) .compileComponents(); // compile template and css })); beforeEach(()=> { //And here is the synchronous async function fixture = TestBed.createComponent(PastebinComponent); comp = fixture.componentInstance; de = fixture.debugElement.query(By.css('.pastebin')); element = de.nativeElement; });
Мы еще не написали никаких тестовых спецификаций. Тем не менее, это хорошая идея, чтобы заранее составить схему спецификаций. На рисунке ниже изображен грубый дизайн компонента Pastebin.

Нам нужно написать тесты со следующими ожиданиями.
- Компонент Pastebin должен существовать.
- Свойство title компонента должно отображаться в шаблоне.
- Шаблон должен иметь таблицу HTML для отображения существующих паст.
-
pastebinService
вводится в компонент, и его методы доступны. - Пасты не должны отображаться до тех пор, пока не вызывается
onInit()
. - Пасты не отображаются до тех пор, пока обещание в нашем Service не будет разрешено.
Первые три теста легко реализовать.
it('should have a Component',()=> { expect(comp).toBeTruthy(); }); it('should have a title', () => { comp.title = 'Pastebin Application'; fixture.detectChanges(); expect(element.textContent).toContain(comp.title); }) it('should have a table to display the pastes', () => { expect(element.innerHTML).toContain("thead"); expect(element.innerHTML).toContain("tbody"); })
В тестовой среде Angular автоматически не связывает свойства компонента с элементами шаблона. Вы должны явно вызвать fixture.detectChanges()
каждый раз, когда вы хотите связать свойство компонента с шаблоном. Запуск теста должен дать вам ошибку, потому что мы еще не объявили свойство title внутри нашего компонента.
title: string = "Pastebin Application";
Не забудьте обновить шаблон базовой структурой таблицы.
<div class = "pastebin"> <h2> {{title}}</h2> <table id="table" class="table table-hover table-striped"> <thead> <tr> <th> id </th> <th> Title </th> <th> Language </th> <th> Code </th> </tr> </thead> <tbody> </tbody> </table> </div>
Что касается остальных случаев, нам нужно ввести Pastebinservice
и написать тесты, которые касаются взаимодействия между компонентами. Реальная служба может совершать вызовы на удаленный сервер, а вставить ее в необработанную форму будет весьма сложной задачей.
Вместо этого мы должны написать тесты, в которых основное внимание будет сосредоточено на том, взаимодействует ли компонент с сервисом, как ожидалось. Мы добавим спецификации, которые будут следить за pastebinService
и его методом getPastebin()
.
Во-первых, импортируйте PastebinService
в наш тестовый набор.
import { PastebinService } from '../pastebin.service';
Затем добавьте его в массив providers
внутри TestBed.configureTestingModule()
.
TestBed.configureTestingModule({ declarations:[ CreateSnippetComponent], providers: [ PastebinService ], });
В приведенном ниже коде создается шпион Jasmine, который предназначен для отслеживания всех вызовов метода getPastebin()
и возвращает обещание, которое немедленно разрешается в mockPaste
.
//The real PastebinService is injected into the component let pastebinService = fixture.debugElement.injector.get(PastebinService); mockPaste = [ { id:1, title: "Hello world", language: "Ruby", paste: "puts 'Hello'" }]; spy = spyOn(pastebinService, 'getPastebin') .and.returnValue(Promise.resolve(mockPaste));
Шпион не заботится о деталях реализации реального сервиса, но вместо этого перехватывает любой вызов фактического метода getPastebin()
. Более того, все удаленные вызовы, скрытые внутри getPastebin()
, игнорируются нашими тестами. Во второй части учебника мы будем писать изолированные модульные тесты для сервисов Angular.
Добавьте следующие тесты в pastebin.component.spec.ts
.
it('should not show the pastebin before OnInit', () => { this.tbody = element.querySelector("tbody"); //Try this without the 'replace(\s\s+/g,'')' method and see what happens expect(this.tbody.innerText.replace(/\s\s+/g, '')).toBe("", "tbody should be empty"); expect(spy.calls.any()).toBe(false, "Spy shouldn't be yet called"); }); it('should still not show pastebin after component initialized', () => { fixture.detectChanges(); // getPastebin service is async, but the test is not. expect(this.tbody.innerText.replace(/\s\s+/g, '')).toBe("", 'tbody should still be empty'); expect(spy.calls.any()).toBe(true, 'getPastebin should be called'); }); it('should show the pastebin after getPastebin promise resolves', async() => { fixture.detectChanges(); fixture.whenStable().then( () => { fixture.detectChanges(); expect(comp.pastebin).toEqual(jasmine.objectContaining(mockPaste)); expect(element.innerText.replace(/\s\s+/g, ' ')).toContain(mockPaste[0].title); }); })
Первые два теста - это синхронные тесты. Первая спецификация проверяет, остается ли innerText
элемента div
пустым, пока компонент не инициализирован. Второй аргумент функции матчера Jasmine является необязательным и отображается, когда тест терпит неудачу. Это полезно, если в спецификации есть несколько ожидающих операторов.
Во втором spec компонент инициализируется (поскольку вызывается fixture.detectChanges()
), и ожидается, что шпион будет вызван, но шаблон не должен обновляться. Несмотря на то, что шпион возвращает разрешенное обещание, mockPaste
пока недоступен. Он не должен быть доступен, если тест не является асинхронным.
В третьем тесте используется функция async()
, обсуждавшаяся ранее, для запуска теста в тестовой зоне асинхронного тестирования. async()
используется для синхронного тестирования асинхронного. fixture.whenStable()
вызывается, когда все ожидающие асинхронные действия выполнены, а затем вызывается второй раунд fixture.detectChanges()
для обновления DOM с новыми значениями. Ожидание в финальном тесте гарантирует, что наш DOM обновляется с помощью значений mockPaste
.
Чтобы пройти тесты, нам необходимо обновить наш pastebin.component.ts
следующим кодом.
/*pastebin.component.ts*/ import { Component, OnInit } from '@angular/core'; import { Pastebin } from '../pastebin'; import { PastebinService } from '../pastebin.service'; @Component({ selector: 'app-pastebin', templateUrl: './pastebin.component.html', styleUrls: ['./pastebin.component.css'] }) export class PastebinComponent implements OnInit { title: string = "Pastebin Application"; pastebin: any = []; constructor(public pastebinServ: PastebinService) { } //loadPastebin() is called on init ngOnInit() { this.loadPastebin(); } public loadPastebin() { //invokes pastebin service's getPastebin() method and stores the response in `pastebin` property this.pastebinServ.getPastebin().then(pastebin => this.pastebin = pastebin); } }
Также необходимо обновить шаблон.
<!--- pastebin.component.html --> <div class = "pastebin"> <h2> {{title}}</h2> <table id="table" class="table table-hover table-striped"> <thead> <tr> <th> id </th> <th> Title </th> <th> Language </th> <th> Code </th> </tr> </thead> <tbody> <tr *ngFor="let paste of pastebin"> <td> {{paste.id}} </td> <td> {{paste.title}} </td> <td> {{paste.language}} </td> <td> View code </td> </tr> </tbody> <!--- <app-add-paste (addPasteSuccess)= 'onAddPaste($event)'> </app-add-paste> --> </table> </div>
Добавление новой пасты
Создайте компонент AddPaste с помощью Angular-CLI. На рисунке ниже изображен дизайн компонента AddPaste.
Логика компонента должна соответствовать следующим спецификациям.
- Шаблон компонента AddPaste должен иметь кнопку Create Paste.
- Нажатие кнопки Create Paste должно отображать модальный блок с идентификатором 'source-modal'.
- Действие click также должно обновить свойство
showModal
компонента вtrue
. (showModal
- это логическое свойство, которое становится истинным, когда модальное окно отображается и false, когда оно закрывается.) - Нажатие кнопки save вызовет метод
addPaste()
службы Pastebin. - При нажатии кнопки close следует удалить идентификатор 'source-modal' из DOM и обновить свойство
showModal
вfalse
.
Мы разработали первые три теста для вас. Посмотрите, проходят ли они успешно.
describe('AddPasteComponent', () => { let component: AddPasteComponent; let fixture: ComponentFixture<AddPasteComponent>; let de: DebugElement; let element: HTMLElement; let spy: jasmine.Spy; let pastebinService: PastebinService; beforeEach(async(() => { TestBed.configureTestingModule({ declarations: [ AddPasteComponent ], imports: [ HttpModule, FormsModule ], providers: [ PastebinService ], }) .compileComponents(); })); beforeEach(() => { //initialization fixture = TestBed.createComponent(AddPasteComponent); pastebinService = fixture.debugElement.injector.get(PastebinService); component = fixture.componentInstance; de = fixture.debugElement.query(By.css('.add-paste')); element = de.nativeElement; spy = spyOn(pastebinService, 'addPaste').and.callThrough(); //ask fixture to detect changes fixture.detectChanges(); }); it('should be created', () => { expect(component).toBeTruthy(); }); it('should display the `create Paste` button', () => { //There should a create button in the template expect(element.innerText).toContain("create Paste"); }); it('should not display the modal unless the button is clicked', () => { //source-model is an id for the modal. It shouldn't show up unless create button is clicked expect(element.innerHTML).not.toContain("source-modal"); }) it("should display the modal when 'create Paste' is clicked", () => { let createPasteButton = fixture.debugElement.query(By.css("button")); //triggerEventHandler simulates a click event on the button object createPasteButton.triggerEventHandler("click",null); fixture.detectChanges(); expect(element.innerHTML).toContain("source-modal"); expect(component.showModal).toBeTruthy("showModal should be true"); }) })
DebugElement.triggerEventHandler()
- единственное новое для вас. Он используется для запуска события клика на элемент кнопки, на который он вызывается. Второй параметр - это объект события, и мы оставили его пустым, так как click()
компонента не ожидает его.
Резюме
Вот и все. В этой первой статье мы узнали:
- как настроить и настроить Jasmine и Karma
- как написать базовые тесты для классов
- как проектировать и писать модульные тесты для компонентов
- как создать базовый сервис
- как использовать утилиты тестирования Angular в нашем проекте
В следующем уроке мы создадим новые компоненты, напишем больше тестовых компонентов с входными данными, сервисами и маршрутами. Оставайтесь с нами во второй части серии. Поделитесь своими мыслями в комментариях.
Subscribe below and we’ll send you a weekly email summary of all new Code tutorials. Never miss out on learning about the next big thing.
Update me weeklyEnvato Tuts+ tutorials are translated into other languages by our community members—you can be involved too!
Translate this post