Мощный инструмент для упрощения ваших угловых тестов
Spectator помогает вам избавиться от всей работы с шаткой, оставляя вам читаемые, гладкие и оптимизированные модульные тесты.
✅ Поддержка тестирования угловых компонентов, директив и услуг
✅ Легкие запросы DOM
✅ Чистый API для запуска клавиатуры/мышью/сенсорных событий
✅ Тестирование ng-content
✅ Пользовательские маткеры Jasmine/Jest (Tohaveclass, Tobedisabled ..)
✅ Поддержка тестирования маршрутизации
✅ Поддержка тестирования HTTP
✅ Встроенная поддержка компонентов входа
✅ Встроенная поддержка поставщиков компонентов
✅ Поставщики автоматического сцепления
✅ сильно напечатано
✅ Оподница Jest
Спонсорская помощь в дальнейшей разработке и обслуживании библиотек NGNEAT. Подумайте о том, чтобы попросить вашу компанию спонсировать NGNEAT в качестве основы для их бизнеса и разработки приложений.
Поднимите свою поддержку, став золотым спонсором, и вы получите свой логотип на нашем Readme в 5 лучших репозиториях.
Поднимите свою поддержку, став золотым спонсором и наслаждайтесь центром внимания с вашим логотипом, заметно продемонстрированным в топ -3 репозиториях в нашем Readme.
Станьте спонсором бронзы и получите свой логотип на нашем Readme на GitHub.
Функции
Оглавление
Установка
Npm
Пряжа
Тестирование компонентов
Вложенные отложенные взгляды
Селектор строк
Селектор типа
DOM SELECTER
Тестирование выбранных элементов
Измешные компоненты
Тестирование однокомпонентных/директивных угловых модулей
Пользовательские события
Создатели событий
События API
Помощники клавиатуры
Мышиные помощники
Запросы
Отступные взгляды
Тестирование с хостом
Пользовательский компонент хоста
Тестирование с маршрутизацией
Запускает навигацию
Интеграционное тестирование с RouterTestingModule
Параметры маршрутизации
Директивы тестирования
Службы тестирования
Дополнительные варианты
Тестирование труб
Использование пользовательского компонента хоста
Перспективные поставщики
Издевающиеся от инитных зависимостей
Измешные зависимости конструктора
Jest Support
Тестирование с http
Глобальные инъекции
Поставщики компонентов
Пользовательские совпадения
Схема
Коллекция схем по умолчанию
Рабочий зритель и Jest Sample Repo и Carma Сравнение
Основная команда
Участники
npm install @ngneat/spectator --save-dev
yarn add @ngneat/spectator --dev
Создайте компонентную фабрику, используя функцию createComponentFactory()
, передавая класс компонентов, который вы хотите проверить. createComponentFactory()
возвращает функцию, которая создаст свежий компонент в каждом блоке it
:
Import {Spectator, CreateComponentFactory} из '@ngneat/spectator'; import {buttoncomponent} от './button.component'; describe(''buttoncomponent', () => { Пусть Spectator: Spectator <ThoutkComponent>; const createComponent = createComponentFactory (ButtonComponent); oopeach (() => spectator = createComponent ()); это ('должен иметь успешный класс по умолчанию', () => {weall (spectator.query ('button')). tohaveclass ('успех'); }); Это («должно установить имя класса в соответствии с входом [classname]», () => {Spectator.setInput ('className', 'Danger'); ожидаете (Spectator.Query ('button')). tohaveClass (' Опасность '); ожидайте (Spectator.Query (' button ')). not.tohaveClass (' успех '); });});
Функция createComponentFactory
может при планировании принять следующие параметры, которые расширяют базовые параметры модуля Angular Testing:
const createComponent = createComponentFactory ({ Компонент: Buttoncomponent, импорт: [], поставщики: [], Объявления: [], intryComponents: [], ComponentProviders: [], // переопределить поставщиков компонента ComponentViewProviders: [], // переопределить поставщиков представления компонента переопределения: [], // переопределить модули Переоткрытые компоненты: [], // переопределить компоненты в случае тестирования автономного компонента Удаленныерективы: [], // Переопределение директив в случае тестирования автономной директивы Переопределения: [], // переопределить трубы в случае тестирования автономной трубы Mocks: [], // поставщики, которые будут автоматически высмеивать ComponentMocks: [], // поставщики компонентов, которые будут автоматически высмеиваться ComponentViewProvidersMocks: [], // Поставщики компонента просмотра, которые будут автоматически издеваться DeTectChanges: false, // по умолчанию к истинному DeclareComponent: False, // по умолчанию инвалиды: неверно, // по умолчанию мелкий: верно, // по умолчанию ложно DEFERBLOCKBEHAVIOR: DEFERBLOCKBEHAVIOR // По умолчанию DEFERBLOCKBEHAVIOR.PlayThrough});
Функция createComponent()
необязательно принимает следующие параметры:
это ('должен ...', () => { Spectator = createComponent ({// Компонент inputsProps: {title: 'Щелкни}, // переопределить поставщиков компонента // Обратите внимание, что вы должны объявить его один раз в `createComponentFactory`providers: [], // Запустить выявление изменений (по умолчанию к истинно }); ожидайте (Spectator.query ('button')). tohavetext ('click');});
Предоставляя варианты overrideComponents
в рамках нашей функции createComponent()
мы можем определить способ переоценки отдельных компонентов и его зависимостей
@Component ({ Селектор: `app-standalone-with-import`, Шаблон: `<div id =" standalone "> автономный компонент с импортом! </div> <app-standalone-with-зависимость Импорт: [STANDALONECOMPONENTWITHDEPEDENDINENTY], автономный: true,}) класс экспорта STANDALONEWITHIMPORTSCONONTENT {} @Component ({ Селектор: `app-standalone-with-зависимость Шаблон: `<div id =" standalonewithDependency "> автономный компонент с зависимостью! </div>`, автономный: true,}) export class stancalonecomponentWithDependency { Constructor (public Query: queryService) {}}@component ({{ Селектор: `app-standalone-with-зависимость Шаблон: `<div id =" standalonewithDependency "> автономный компонент с зависимостью переопределения! </div>`, Автономный: true,}) класс экспорта MockstandalonecomponentWithDependency { Constructor () {}} it ('должен ...', () => { const spectator = createhostfactory ({component: standalonewithimportscomponent, шаблон: `<div> <app-standalone-with-import> </app-standalone-with-import> </div>`, переопределения: [[SperintAloneWithimportscomponer, {Удалить: {imports: [stancalonecomponentwithDependency]}, добавить: {imports: [mockstandalonecomponentWithDependency]},},],],], }); ожидайте (host.query ('#standalone')). tocontaintext ('автономный компонент с импортом!'); weals (host.query ('#standalonewithDependency')). TocontainText ('автономный компонент с зависимостью переопределения!');});
Метод createComponent()
возвращает экземпляр Spectator
, который раскрывает следующий API:
fixture
- тестированное приспособление компонента
component
- экземпляр тестированного компонента
element
- тестируемый натуральный элемент компонента
debugElement
- Элемент отладки тестированного приспособления
flushEffects()
- Предоставляет обертку для TestBed.flushEffects()
inject()
- предоставляет обертку для TestBed.inject()
:
const service = spectator.inject (queryservice); const forcomponentinjector = true; const service = spectator.inject (QueryService, fromComponentinjector);
detectChanges()
- Запускает DETECTCHANGES на протестированном элементе/хосте:
Spectator.detectChanges ();
detectComponentChanges()
- Запускает detectChanges
на тестируемом компоненте (не на host
). Вам понадобится этот метод в редких случаях при использовании host
, а протестированный компонент - это onPush
, и вы хотите заставить его запустить цикл обнаружения изменений.
Spectator.detectComponentChanges ();
setInput()
- изменяет значение @Input () тестируемого компонента. Метод запускает ngOnChanges
с SimpleChanges
вручную, если он существует.
это ('должен ...', () => { Spectator.SetInput ('className', 'Danger'); Spectator.setInput ({className: 'Danger' });});
output
- возвращает наблюдаемый @Output () тестируемого компонента:
это ('должен издать событие $ на клике', () => { пусть вывод; Spectator.Output ('Щелкни «нажмите»). Подписаться (result => (output = result)); Spectator.component.onclick ({type: 'click'}); Ожидайте (output) .toequal ({type: 'click'});});
tick(millis?: number)
- запустите функцию fakeasync tick()
и вызов detectChanges()
:
это ('должен работать с Tick', fakeasync (() => { Spectator = createComponent (ZippyComponent); Spectator.component.update (); Ожидайте (Spectator.component.updatedAsync) .tobaLsy (); Spectator.tick (6000); Ожидайте (Spectator.component.updatedAsync) .not.tobefalsy ();}))
Каждое из событий может принять SpectatorElement
, которое может быть одним из следующих:
Тип SpectatorElement = String | Элемент | Debugelement | ElementRef | Окно | Документ | Домсектор;
Если не предоставлен, элемент по умолчанию будет элементом хоста тестируемого компонента.
click()
- запускает событие Click:
Spectator.click (SpectatorElement); Spectator.click (byText ('element'));
blur()
- запускает размытие:
Spectator.blur (SpectatorElement); Spectator.blur (byText ('element'));
Обратите внимание, что при использовании фреймворка Jest Blur () работает только в том случае, если элемент сфокусирован. Подробности.
focus()
- запускает фокус -событие:
Spectator.focus (SpectatorElement); Spectator.focus (byText ('element'));
typeInElement()
- моделирование пользователя typing:
Spectator.typeinelement (значение, SpectatorElement); Spectator.TypeInelement (значение, ByText ('element'));
dispatchMouseEvent()
- запускает мышь: событие:
Spectator.dispatchmouseevent (SpectatorElement, 'mouseout'); Spectator.dispatchmouseevent (SpectatoreLement, 'mouseout'), x, y, event); Spectator.dispatchmouseevent (bytext ('element'), 'mouseout'); Spectator.dispatcheventevent (bytext ('element'), 'mouseout'); Spectator.dispatch ('Element'), 'mouseout', x, y, event);
dispatchKeyboardEvent()
- запускает событие клавиатуры:
Spectator.dispatchkeyboardevent (SpectatorElement, 'keyup', 'Escape'); Spectator.dispatchkeyboardevent (SpectatorElement, 'keyup', {key: 'Escape', Keycod ',' Escape '); Spectator.dispatchkeyboardevent (bytext (' element '),' keyup ', {key:' recape ', key -код: 27})
dispatchTouchEvent()
- запускает сенсорное событие:
Spectator.DispatchTouchEvent (SpectatorElement, Type, X, Y); Spectator.DispatchTouchEvent (byText ('element'), type, x, y);
Вы можете запустить пользовательские события (@Output () дочерних компонентов), используя следующий метод:
Spectator.triggereventhandler (mychildcomponent, 'mycustomevent', 'EventValue'); Spectator.triggereventhandler (mychildComponent, 'mycustomevent', 'EventValue', {root: true}); Spectator.triggereVenthandl ',' EventValue '); Spectator.triggereventhandler (' App-Child-Component ',' MyCustomeVent ',' EventValue ', {root: true});
Если вы хотите протестировать события независимо от любого шаблона (например, в службах докладчиков), вы можете отступить на базовых создателях событий. Они в основном обеспечивают ту же подпись без предыдущего элемента.
const keyboardevent = createkeyboardevent ('keyup', 'rrowdown'/ *, targetElement */); const mouseevent = createMouseEvent ('mouseout'); const touchEvent = createTouchEvent ('touchmove'); const fakeEvent = createFakeEvent ('input');
Spectator.keyboard.pressenter (); Spectator.keyboard.presseScape (); Spectator.keyboard.presstab (); Spectator.keyboard.pressbackspace (); Spectator.keyboard.presskey ('a'); Spectator.keyboard. ctrl.a '); Spectator.keyboard.presskey (' ctrl.shift.a ');
spectator.mouse.contextmenu ('. Selector'); Spectator.mouse.dblclick ('. Selector');
Обратите внимание, что каждый из вышеперечисленных методов также будет работать detectChanges()
.
API Spectator включает в себя удобные методы запроса DOM как часть теста: query
, queryAll
, queryLast
, queryHost
и queryHostAll
. Все методы запроса являются полиморфными и позволяют вам запросить, используя любой из следующих методов.
Передайте селектор строк (в том же стиле, что и при использовании jQuery или Document.queryselector), чтобы запросить элементы, которые соответствуют этому пути в DOM. Этот метод для запроса эквивалентен предикату Angular. Обратите внимание, что нативные элементы HTML будут возвращены. Например:
// Возвращает один htmlelementementsepectator.query ('div> ul.nav li: первой ребенок'); // Возвращает массив всех соответствующих htmlelementssepectator.queryall ('div> ul.nav li'); // Запрос из Document contextexpectator.query ('div', {root: true}); spectator.query ('app-child', {read: childserviceservice});
Передайте тип (например, компонент, директива или класс поставщиков), чтобы запросить экземпляры такого типа в DOM. Это эквивалентно By.directive
предикату. При желании вы можете пройти второй параметр, чтобы прочитать определенный токен впрыска от форсунок соответствующих элементов. Например:
// Возвращает один экземпляр myComponent (если присутствует) Spectator.Query (myComponent); // Возвращает экземпляр «someService», найденного в экземпляре `mycomponent`, который существует в Dom (если присутствует) Spectator.query (myComponent , {read: someservice}); Spectator.query (myComponent, {read: elementRef}); host.querylast (ChildComponent); host.queryall (ChildComponent);
Spectator позволяет вам запросить элементы, используя селекторы, вдохновленные Dom-тестированием. Доступные селекторы:
Spectator.query (byplaceholder ('Пожалуйста, введите свой адрес электронной почты)); Spectator.query (byvalue (' by value ')); Spectator.query (bytitle (' по названию ')); Spectator.query (byalttext (' by by by by by by by by by by by by by by by by by by byt Alt Text ')); Spectator.query (bylabel (' by label ')); Spectator.query (bytext (' по тексту ')); Spectator.query (bytext (' по тексту ', {selector:' #some. selector '})); spectator.query (byTextContent (' by Text Content ', {selection:' #some .selector '})); Spectator.query (byrole (' fackbox ', {cherced: true}));
Разница между byText
и byTextContent
состоит в том, что первый не соответствует тексту внутри вложенных элементов.
Например, в этом следующем html byText('foobar', {selector: 'div'})
не будет соответствовать следующему div
, но byTextContent
Will:
<div> <pran> foo </span> <pran> bar </span> </div>
Spectator позволяет вам запросить вложенные элементы в родительском элементе. Это полезно, когда у вас есть несколько экземпляров одного и того же компонента на странице, и вы хотите запросить детей в пределах определенного. Родительский селектор - это селектор строк, который используется для поиска родительского элемента. Родительский селектор передается в качестве второго параметра для методов запроса. Например:
Spectator.Query (ChildComponent, {haryLectector: '#Parent-Component-1'}); Spectator.queryall (ChildComponent, {harientLector: '#Parent-Component-1'});
Spectator позволяет легко протестировать <select></select>
Elements и поддерживает Multi Select.
Пример:
это ('должен установить правильные параметры на Multi Select', () => { const select = spectator.query ('#test-multi-select') как htmlsectelement; Spectator.selectoption (select, ['1', '2']); Ожидайте (select) .tohaveselectedoptions (['1', '2']);}); it ('должен установить правильную опцию на стандартном выборе', () => { const select = spectator.query ('#test-singlect') как htmlselectelement; Spectator.selectoption (Select, '1'); Ожидайте (select) .tohaveselectedoptions ('1');});
Это также позволяет вам проверить, действует ли ваш обработчик событий change
правильно для каждого выбранного элемента. Вы можете отключить это, если вам нужно предварительно установить варианты, не отправляя событие изменения.
API:
Spectator.selectoption (SelectElement: htmlSelectelement, параметры: String | String [] | htmloptionElement | htmloptionElement [], config: {eMitevents: boolean} = {eMitevents: true});
Пример:
это ('должно отправить правильное количество событий изменения', () => { const onchaspy = spyon (Spectator.component, 'handlechange'); const select = spectator.query ('#test-onchange-select') как htmlSelectelement; Spectator.selectoption (select, ['1', '2'], {eMitevents: true}); Ожидайте (select) .tohaveselectedoptions (['1', '2']); Ожидайте (Onchaspy) .tohavebeencalledTimes (2);}); it ('не должно отправлять правильное количество событий изменений', () => { const onchaspy = spyon (Spectator.component, 'handlechange'); const select = spectator.query ('#test-onchange-select') как htmlSelectelement; Spectator.selectoption (select, ['1', '2'], {eMitevents: false}); Ожидайте (select) .tohaveselectedoptions (['1', '2']); Ожидайте (Onchaspy) .not.tohavebeencalledTimes (2);});
Вы также можете передавать HTMLOptionElement
(ы) в качестве аргументов для selectOption
и совместного сочетания toHaveSelectedOptions
. Это особенно полезно, когда вы используете привязку [ngValue]
на <option>
:
это ('должен установить правильный вариант на одном выборе при прохождении элемента', () => { const select = spectator.query ('#test-single-select-element') как htmlsectelement; Spectator.selectoption (select, spectator.query (bytext ('два')) как htmloptionElement); Ожидайте (select) .tohaveselectedoptions (Spectator.Query (byText ('два')) как htmloptionElement);});
Если вам нужно издеваться над компонентами, вы можете использовать библиотеку NG-Mocks. Вместо использования CUSTOM_ELEMENTS_SCHEMA
, который может скрыть некоторые проблемы и не поможет вам установить входы, выходы и т. Д., ng-mocks
будут автоматически измерять входные данные, выходы и т. Д. Для вас.
Пример:
import {createhostfactory} от '@ngneat/spectator'; import {mockcomponent} от 'ng-mocks'; import {foocomponent} из './path/to/foo.component'; constast = createhostfactory ({{{{{{{{{{{{{{{{{{{{{{ Компонент: yourcomponenttotest, Объявления: [MockComponent (Foocomponent) ]});
Компоненты (или директивы), которые объявляются в их собственном модуле, могут быть проверены путем определения компонентного модуля в списке импортов на заводе компонентов вместе с компонентом. Например:
const createComponent = createComponentFactory ({ Компонент: Buttoncomponent, Импорт: [ButtonComponentModule],});
Однако при использовании этого зрителя внутренне добавляет компонент ButtonComponent
к объявлениям внутреннего созданного нового модуля. Следовательно, вы увидите следующую ошибку:
Type ButtonComponent is part of the declarations of 2 modules [...]
Можно сказать Spectator не добавлять компонент в объявления внутреннего модуля и вместо этого использовать явно определенный модуль, как есть. Просто установите свойство declareComponent
Options Factory на false
:
const createComponent = createComponentFactory ({ Компонент: Buttoncomponent, Импорт: [ButtonComponentModule], DeclareComponent: false,});
При использовании CentreiRectiveFactory установите свойство declareDirective
на заводских параметров на false
:
const createmirective = creatirectiveFactory ({ Компонент: ightingComponent, Импорт: [ightingComponentModule], Decledirective: false,});
Зритель предоставляет удобный API для доступа к отсроченным представлениям ( @defer {}
).
Получите доступ к нужному блоку отсрочки с помощью метода spectator.deferBlock(optionalIndex)
. Параметр optionalIndex
является необязательным и позволяет указать индекс блока DEFE, к которому вы хотите получить доступ.
Доступ к первым блокам отсрочки : просто вызовите spectator.deferBlock()
.
Доступ к последующим блокам отсрочки : используйте соответствующий индекс в качестве аргумента. Например, spectator.deferBlock(1)
обращается к второму блоку (индексация на основе нуля).
spectator.deferBlock(optionalIndex)
возвращает четыре метода для рендеринга различных состояний указанного блока отсрочки:
renderComplete()
- Образует полное состояние блока отсрочки.
renderPlaceholder()
- Образует заполнитель штата Блок отсрочки.
renderLoading()
- рендерирует состояние загрузки блока отсрочки.
renderError()
- рендерирует состояние ошибки блока отсрочки.
Пример:
@Component ({selector: 'app-cmp', шаблон: `@defer (on viewport) {<div> Полное состояние первого блока Defer </div> <!-Parent Complete->} @placeholder { <div> Placeholder </div>} `,}) класс DummyComponent {} const createComponent = createComponentFactory ({Component: DummyComponent, defflockbehavior: deferblockbehavior.manual,}); It ('должен рендер > {// Организация const spectator = createComponent ();
Чтобы получить доступ к состояниям в пределах вложенных блоков отсрочки, вызовите метод deferBlock
цепляясь из возвращенного метода состояния блока.
Пример: доступ к вложенному полному состоянию:
// Предполагая `spectator.deferblock (0) .renderComplete ()` reders полное состояние родительского отряда blockconst parentcompletestate = wait spectator.deferblock (). = await parentcompletestate.rendercomplete (). deferblock ();
Полный пример :
@Component ({selector: 'app-cmp', шаблон: `@defer (on viewport) {<div> Полное состояние первого блока Def Полное состояние вложенного блока отсрочки </div> <!-вложенное полное состояние->}} @placeholder {<div> Placeholder </div>} `,}) класс DummyComponent {} const createComponent = createComponentFactory ( {Компонент: DummyComponent, Deferblockbehavior: deferblockbehavior.manual,}); it ('должен сделать первое вложенное полное состояние', async () => {// arrange const spectator = createcomponent (); // act // renders родитель Полное состояние const parentcompletestate = wait spectator.deferblock (). rendercomplete (); defer block ');});
Тестирование компонента с компонентом хоста является более элегантной и мощной техникой для проверки вашего компонента. Это в основном дает вам возможность писать ваши тесты так же, как вы пишете свой код. Посмотрим на это в действии:
Import {createHostFactory, SpectatorHost} из '@ngneat/spectator'; description ('ZippyComponent', () => { Пусть зритель: SpectatorHost <ZippyComponent>; const createhost = createhostfactory (zippycomponent); It ('должен отобразить заголовок из свойства хоста', () => {Spectator = createhost (`<Zippy [title] =" title "> </Zippy>`, {HosterProps: {title: 'Spectator - это круто'} }); weals (spectator.query ('. Zippy__title')). tohavetext ('Spectator - это потрясающее'); }); Это ('должен отображать слово «закрыть», если Open', () => {Spectator = createhost (`<Zippy Title =" Zippy Title "> Zippy Content </Zippy>`); Spectator.click ('. Zippy__title' ); weals (spectator.query ('. rurow')). tohavetext ('close'); weals (spectator.query ('. rurow')). not.tohavetext ('open'); });});
Метод хоста возвращает экземпляр SpectatorHost
, который расширяет Spectator
со следующим дополнительным API:
hostFixture
- приспособление хоста
hostComponent
- экземпляр компонента хоста
hostElement
- нативный элемент хозяина
hostDebugElement
- элемент отладки хоста отладки
setHostInput
- изменяет значение @Input()
компонента хоста
queryHost
- Подробнее о запросе в зрительном виде
queryHostAll
- Подробнее о запросе в Spectator
Настройка входов непосредственно на компонент с использованием setInput
или props
невозможно при тестировании с помощью компонента хоста. Входные данные должны быть установлены через hostProps
или setHostInput
вместо этого и проходить через ваш компонент в шаблоне.
Иногда полезно передать вашу собственную реализацию хоста. Мы можем передать пользовательский компонент хоста в createHostFactory()
, который заменит по умолчанию:
@Component ({selector: 'Custom-Host', Template: ''}) Class CustomShostComponent { title = 'custom hostcomponent';} description ('с пользовательским хост -компонентом', function () { Пусть Spectator: SpectatorHost <ZippyComponent, CustomHostComponent>; const createhost = createhostfactory ({component: ZippyComponent, Host: CustomShostComponent }); It ('должен отобразить заголовок компонента хоста', () => {Spectator = createhost (`<Zippy [title] =" title "> </Zippy>`); ожидаете (Spectator.Query ('. Zippy__title')))) .tohavetext ('Custom HostComponent'); });});
Для компонентов, которые используют маршрутизацию, имеется специальная заводская завод, которая расширяет по умолчанию и предоставляет загрязненный ActivatedRoute
, чтобы вы могли настроить дополнительные параметры маршрутизации.
описать ('ProductDetailScomponent', () => { Пусть Spectator: SpectatorRouting <productDetailScomponent>; const createComponent = createroutingFactory ({Component: ProductDetailScomponent, Params: {ProductId: '3'}, Data: {title: 'некоторые заголовок'} }); oopeach (() => spectator = createComponent ()); It ('должен отображать название данных маршрута }); Это ('должен реагировать на изменения маршрута', () => {Spectator.setRouteParam ('ProductId', '5'); // Ваш тест здесь ... });});
API SpectatorRouting
содержит удобные методы обновления текущего маршрута:
Интерфейс SpectatorRouting <c> расширяет Spectator <c> { /*** Моделирует навигацию по маршруту путем обновления параметров, Queryparams и наблюдаемых потоков данных. */ TriggerNavigation (варианты?: RouteOptions): void; /*** Обновляет маршрут параметры и запускает навигацию по маршруту. */ setRouteParam (name: string, value: string): void; /*** Обновляет параметры запроса маршрута и запускает навигацию по маршруту. */ setRoutequeryparam (name: string, value: string): void; /*** Обновляет данные маршрута и запускает навигацию по маршруту. */ setRoutedata (имя: строка, значение: any): void; /*** Обновляет фрагмент маршрута и запускает навигацию по маршруту. */ setRouteFragment (фрагмент: строка | null): void; /*** Обновляет URL -адрес маршрута и запускает навигацию по маршруту. */ setRouteUrl (url: urlsegment []): void;}
RouterTestingModule
Если вы установите опцию stubsEnabled
на false
, вы можете передать реальную конфигурацию маршрутизации и настроить интеграционный тест, используя RouterTestingModule
из Angular.
Обратите внимание, что это требует обещаний для решения. Один из способов справиться с этим - это сделать тест асинхронности:
Описать ('Test Test Integration Test', () => { const createComponent = createroutingFactory ({Component: MyComponent, объявления: [otherComponent], StubSenabled: false, маршруты: [{path: '', компонент: mycomponent}, {path: 'foo', компонент: othercomponent}]] }); Это ('должен уйти в сторону с помощью ссылки на маршрутизатор', async () => {const spectator = createComponent (); // ждать обещаний разрешить ... ждать Spectator.fixture.whenstable (); // Проверка текущего маршрута Утверждая LocationExpect (Spectator.Inject (location) .path ()). Tobe ('/'); // Нажмите на маршрутизатор Linksepectator.click ('. Link-1'); // Не забудьте ждать обещает разрешить ... ждать Spectator.fixture.whenStable (); // Проверка новый маршрут, утверждая LocationExpect (Spectator.inject (location) .path ()). tobe ('/foo'); });});
Функция createRoutesFactory
может принять следующие параметры, сверху параметра зрителя по умолчанию:
params
: начальные параметры для использования в ActivatedRoute
Stub
queryParams
: начальные параметры запроса для использования в ActivatedRoute
Stub
data
: начальные данные для использования в ActivatedRoute
Stub
fragment
: начальный фрагмент для использования в ActivatedRoute
Stub
url
: начальные сегменты URL для использования в ActivatedRoute
Stub
root
: Значение для root
для заглушки ActivatedRoute
parent
: значение для parent
для заглушки ActivatedRoute
children
: ценность для children
для ActivatedRoute
Stub
firstChild
: значение для firstChild
для ActivatedRoute
Stub
stubsEnabled
(по умолчанию: true
): включает ActivatedRoute
STUB, если установлен на false
он использует RouterTestingModule
вместо этого
routes
: если stubsEnabled
установлен на False, вы можете передать конфигурацию Routes
для RouterTestingModule
Существует специальная фабрика для тестирования. Допустим, у нас есть следующая директива:
@Directive ({selector: '[highting]'}) класс Export hightingDirective { @Hostbinding ('style.background-color') founalcolor: string; @Hostlistener ('mouseover') onhover () {this.backgroundcolor = '#000000'; } @Hostlistener ('mouseout') onleave () {this.backgroundcolor = '#ffffff'; }}
Давайте посмотрим, как мы можем легко проверить директивы с зрителем:
описать ('hightdirective', () => { Пусть зритель: Spectatordirective <mostdirective>; const createmirective = createirectiveFactory (ightingDirective); ofeeach (() => {Spectator = ceneleIgective (`<div hoald> testing hight hight directive </div>`); }); Это ('должен изменить цвет фона', () => {Spectator.dispatchmouseevent (Spectator.element, 'mouseover'); ожидаете (Spectator.element) .tohavestyle ({foangycolor: 'rgba (0,0,0, 0,1 ) '}); Spectator.dispatchmouseevent (Spectator.Element,' mouseout '); weals (spectator.element) .tohavestyle ({nudecolor:' #fff '}); }); это ('должен получить экземпляр', () => {const instance = spectator.directive; way (exant) .tobedefined (); });});
Настройка входов непосредственно на директиве с использованием setInput
или props
невозможно. Входные данные должны быть установлены через hostProps
или setHostInput
вместо этого и проходить в вашу директиву в шаблоне.
В следующем примере показано, как проверить службу с Spectator:
Import {createServiceFactory, Spectatorservice} из '@ngneat/spectator'; import {authservice} из 'auth.service.ts'; description ('outservice', () => { Пусть Spectator: Spectatorservice <authservice>; const createService = createServiceFactory (AuthService); ofeeach (() => spectator = createService ()); это ('не должен регистрироваться в', () => {wearm (spectator.service.isloggedin ()). tobefalsy (); });});
Функция createService()
возвращает SpectatorService
со следующими свойствами:
service
- Получите экземпляр службы
inject()
- прокси для углового TestBed.inject()
Также возможно передать объект с опциями. Например, при тестировании услуги вы часто хотите издеваться над его зависимостями, поскольку мы сосредотачиваемся на тестируемой службе.
Например:
@Injectable () export class aturservice { Конструктор (частный датчик: датчик) {} isloggedin () {if (this.dateservice.isexpired ('timeStamp')) {return false;} return true; }}
В этом случае мы можем издеваться над зависимостью DateService
.
Import {createServiceFactory, Spectatorservice} из '@ngneat/spectator'; import {authservice} из 'auth.service.ts'; description ('outservice', () => { Пусть Spectator: Spectatorservice <authservice>; const createService = createServiceFactory ({Service: AuthService, Providers: [], intryComponents: [], Mocks: [Dateservice] }); ofeeach (() => spectator = createService ()); это ('должен быть вошел в систему', () => {const dateservice = spectator.inject (dateservice); dateservice.isexpread.and.returnvalue (false); ожидайте (Spectator.service.isloggedin ()). tobetruthy (); });});
В следующем примере показано, как проверить трубу с зрителем:
Import {SpectatorPipe, CreatePipeFactory} от '@ngneat/spectator'; import {statsservice} от './stats.service'; import {sumpipe} от' ./sum.pipe'; describe (''sumpipe ', () => { Пусть Spectator: SpectatorPipe <Sumpipe>; const createPipe = createPipeFactory (Sumpipe); Это ('должен подвести итог данного списка чисел (шаблон)', () => {Spectator = createPipe (`{{[1, 2, 3] | sum}}`); ожидаете (Spectator.element) .tohavetextextextextx ('6'); }); Это ('должен подвести итог данного списка номеров (prop)', () => {Spectator = createPipe (`{{prop | sum}}`, {hostprops: {prop: [1, 2, 3]}}}}}}}}}}}}}} ); ожидайте (Spectator.element) .tohavetext ('6'); }); It ('должен делегировать суммирование в Сервис', () => {const sum = () => 42; const provider = {предоставление: statsservice, usevalue: {sum}}; spectator = createpipe (`{{prop | sum}} `, {hostprops: {prop: [2, 40]}, поставщики: [провайдер]}); ожидается (Spectator.element) .tohavetext ('42 '); });});
Функция createPipe()
возвращает SpectatorPipe
со следующими свойствами:
hostComponent
- экземпляр компонента хоста
debugElement
- элемент отладки приспособления вокруг компонента хоста
element
- собственный элемент компонента хоста
detectChanges()
- прокси для углового TestBed.fixture.detectChanges()
inject()
- прокси для углового TestBed.inject()
Настройка входов непосредственно на трубу с использованием setInput
или props
невозможно. Входные данные должны быть установлены через hostProps
или setHostInput
вместо этого и проходить через вашу трубу в шаблоне.
В следующем примере показано, как проверить трубу, используя пользовательский компонент хоста:
Import {component, input} из '@angular/core'; import {spectatorpipe, createpipefactory} от '@ngneat/spectator'; import {veradypipe} от './agrage.pipe'; import {statsservice} от' ./stats .service ';@component ({ Шаблон: `<div> {{prop | avg}} </div> `}) класс CustomHostComponent { @Input () public prop: number [] = [1, 2, 3];} descript ('veradypipe', () => { Пусть Spectator: SpectatorPipe <средняя труба>; const createPipe = createPipeFactory ({Pipe: MardalPipe, Host: CustomHostComponent }); Это ('должен вычислить среднее значение данного списка чисел', () => {Spectator = createPipe (); ожидаете (Spectator.Element) .tohavetext ('2'); }); Это ('должен привести к 0, когда список чисел пуст', () => {Spectator = createPipe ({hosterprops: {prop: []}}); ожидается (Spectator.element) .tohavetext ('0'); }); It ('должен делегировать расчет в Сервис', () => {const avg = () => 42; const provider = {предоставление: statsservice, usevalue: {avg}}; Spectator = createPipe ({Providers: [Provider ]}); ожидается (Spectator.Element) .tohavetext ('42 '); });});
Для каждой фабрики зрителей мы можем легко издеваться над любым провайдером.
Каждая услуга, которую мы передаем в свойство mocks
, будет насмехаться, используя функцию mockProvider()
. Функция mockProvider()
преобразует каждый метод в жасмин шпион. (т.е. jasmine.createSpy()
).
Вот некоторые из методов, которые он раскрывает:
dateservice.isexpired.and.callthrough (); dateservice.isexpreed.and.callfake (() => Fake); Dateservice.isexpread.and.ThrowerRor ('error'); dateservice.isexpired.andcallfake (() => Fake); ;
Однако, если вы используете Jest в качестве тестовой структуры и хотите вместо этого использовать его механизм насмешческого насмешки, импортируйте mockProvider()
из @ngneat/spectator/jest
. Это автоматически будет использовать функцию jest.fn()
для создания шумового совместимого макета.
mockProvider()
не включает свойства. Если вам нужно иметь свойства на макете, вы можете использовать 2 -й аргумент:
const createService = createServiceFactory ({ Сервис: Authservice, Провайдеры: [MockProvider (orhyervice, {name: 'martin', emittr: new subject (), mockedmethod: () => 'Mocked'}) ],});
Если компонент полагается на то, что служба издевается над методом жизненного цикла Oninit, необходимо отключить обнаружение изменений до тех пор, пока службы не будут введены.
Чтобы настроить это, измените метод createComponent
, чтобы установить опцию detectChanges
для FALSE, а затем вручную detectChanges
на зрителе после настройки введенных услуг.
const createComponent = createComponentFactory ({ Компонент: WeatherDashboardComponent}); It ('должен вызвать API погоды на init', () => { const spectator = createComponent ({DeTectChanges: false }); const weatherservice = Spectator.inject (WeatherDataApi); weatherservice.getweatherdata.andreturn (Of (Mockweatherdata)); Spectator.detectChanges (); Ожидайте (weatherservice.getweatherdata) .tohavebeencalled ();});
Если компонент опирается на то, что сервис издевается в своем конструкторе, вам необходимо создать и настроить макет и обеспечить макет при создании компонента.
const createComponent = createComponentFactory ({ Компонент: WeatherDashboardComponent}); It ('должен вызвать API погоды в конструкторе', () => { const weatherservice = createSpyObject (WeatherDataApi); weatherservice.getweatherdata.andreturn (Of (Mockweatherdata)); Spectator = createComponent ({Providers: [{предоставление: WeatherDataApi, useValue: Weatherservice}] }); Ожидайте (weatherservice.getweatherdata) .tohavebeencalled ();});
По умолчанию Spectator использует Jasmine для создания шпионов. Если вы используете Jest в качестве тестовой структуры, вы можете позволить Spectator создать совместимые с шутками шпионов.
Просто импортируйте одну из следующих функций из @ngneat/spectator/jest
(вместо @ngneat/Spectator), и он будет использовать шутку вместо жасмина. createComponentFactory()
, createHostFactory()
, createServiceFactory()
, createHttpFactory()
, mockProvider()
.
Import {createServiceFactory, Spectatorservice} из '@ngneat/spectator/jest'; import {authservice} от './auth.service'; import {dateservice} от' ./date.service'; describe('authservice ', () => { Пусть Spectator: Spectatorservice <authservice>; const createService = createServiceFactory ({Service: AuthService, Mocks: [Dateservice] }); ofeeach (() => spectator = createService ()); Это ('не должен регистрироваться в', () => {const dateservice = spectator.inject <dateservice> (dateservice); dateservice.isexpired.mockreturnvalue (true); ожидайте (Spectator.service.isloggedin ()). ); }); это ('должен быть вошел в систему', () => {const dateservice = spectator.inject <dateservice> (dateservice); dateservice.isexpread.mockreturnvalue (false); ожидайте (Spectator.service.isloggedin ()). ; });});
При использовании схемы компонента вы можете указать флаг --jest
, чтобы использовать импорт шуста. Чтобы шутить импортировать по умолчанию, обновить angular.json
:
"Схема": {"@ngneat/Spectator: Spectator-Component": {"Jest": true } }
Spectator делает службы тестирования данных, которые используют угловой модуль HTTP, намного проще. Например, допустим, что у вас есть сервис с тремя методами, один выполняет Get, один пост, а один выполняет одновременные запросы:
Экспортный класс todosdataService { Constructor (private httpclient: httpclient) {} getTodos () {return this.httpclient.get ('api/todos'); } posttodo (id: number) {return this.httpclient.post ('api/todos', {id}); } collectTodos () {return merge (this.httpclient.get ('/api1/todos'), this.httpclient.get ('/api2/todos')); }}
Тест для вышеуказанного сервиса должен выглядеть как:
import {createhttpfactory, httpmethod} от '@ngneat/spectator'; import {todosdataservice} от './todos-data.service'; describe('httpclient testing', () => { Пусть зритель: Spectatorhttp <todosdataservice>; const createhttp = createhttpfactory (todosdataservice); ofeeach (() => spectator = createhttp ()); It ('может проверить httpclient.get', () => {spectator.service.gettodos (). specpibe (); spectator.expectone ('api/todos', httpmethod.get); }); It ('может проверить httpclient.post', () => {spectator.service.posttodo (1) .subscribe (); const req = spectator.expectone ('api/todos', httpmethod.post); ожидайте (req. request.body ['id']). Toecoal (1); }); It ('может проверить ток HTTP -запросы', () => {spectator.service.gettodos (). specpibe (); const reqs = spectator.expectconcurrent ([{url: '/api1/todos', метод: httpmethod.getget }, {Url: '/api2/todos', method: httpmethod.get}]); spectator.flushall (reqs, [{}, {}, {}]); });});
Нам нужно создать HTTP Factory, используя функцию createHttpFactory()
, передавая услугу, которую вы хотите протестировать. createHttpFactory()
возвращает функцию, которую можно вызвать, чтобы получить экземпляр Spectatorhttp со следующими свойствами:
controller
- прокси для Angular HttpTestingController
httpClient
- прокси для углового HttpClient
service
- экземпляр службы
inject()
- прокси для углового TestBed.inject()
expectOne()
- Ожидайте, что был сделан единственный запрос, который соответствует данному URL и его методу, и верните его фиктивный запрос
Можно определить инъекции, которые будут доступны для каждого теста без необходимости повторного декларации в каждом тесте:
// test.tsimport {defineglobalsInjections} из '@ngneat/spectator'; import {translocomodule} из '@ngneat/transloco'; defineglobalsinjections ({{{{{{{{{{{{{{{{{ Импорт: [Translocomodule],});
Имейте в виду, что defineGlobalsInjections()
должен быть вызван до загрузки модулей. В угловом test.ts
по умолчанию. Это означает, что перед этой линией:
context.keys (). Map (context);
По умолчанию исходные поставщики компонентов (например, providers
на @Component
) не касаются.
Однако в большинстве случаев вы хотите получить доступ к поставщикам компонента в вашем тесте или заменить их на макет.
Например:
@Component ({ шаблон: '...', поставщики: [fooservice]}) класс Foocomponent { Конструктор (Private Fooservice: Fooservice} {} // ...}
Используйте componentProviders
, чтобы заменить поставщика FooService
:
const createComponent = createComponentFactory ({ компонент: фукомпонент, ComponentProviders: [{Предоставьте: Fooservice, useValue: что -то. ]})
Или издеваться над сервисом, используя componentMocks
:
const createComponent = createComponentFactory ({ компонент: фукомпонент, ComponentMocks: [fooservice]});
Чтобы получить доступ к поставщику, получите его из инжектора компонента, используя параметр fromComponentInjector
:
Spectator.inject (Fooservice, True)
Точно так же вы можете переопределить поставщиков представления компонентов, используя компоненты componentViewProviders
и componentViewProvidersMocks
.
Те же правила также применяются к директивам с использованием параметров directiveProviders
и directiveMocks
.
Ожидайте ('. Zippy__content'). not.toExist (); weals ('. Zippy__content'). Tohavelength (3); ожидайте ('. Zippy ')). )). tohaveproperty ('проверено', true); way (spectator.query ('. img')). tohaveproperty ({src: 'assets/myimg.jpg'}); ожидайте (Spectator.query ('. Img' )). TocontainProperty ({src: 'myimg.jpg'}); // Обратите внимание, что TohaveClass принимает классы только в строгом порядке. Если порядок не имеет значения, отключите строгий режим вручную. Expect ('. Zippy__content'). TohaveClass ('class'); ожидайте ('. Zippy__content '). not.tohaveclass (' class-b, class-a '); way ('. ) .not.tohaveclass (['class-b', 'class-a']); wearm ('. Zippy__content'). tohaveclass ('class', {strict: false}); ожидаете ('. Zippy__content'). tohaveClass ('class-A, Class-B', {strict: false}); ожидаете ('. Zippy__content'). tohaveClass ('class-b, class-a', {strict: false}); ожидаете ('. Zippy__content '). TohaveClass ([' 'class-b', 'class-a'], {strict: false}); weals ('. , {strict: false}); // Обратите внимание, что tohavetext ищет только существование строки, а не в том случае, если строка точно такая же. Если вы хотите убедиться, что строка совершенно одинакова, используйте tohaveExacttext.//, обратите внимание, что если вы хотите проверить, что строка полностью такая же, но сначала используйте TohaveExactTrimmedText.//, что если вы передаете несколько значений, Зритель проверяет текст каждого элемента массива по индексу обнаруженного элемента. Expect ('. Zippy__Content'). Tohavetext ('Content'); ожидаете ('. ']); weals (' ') .tocontainText ([' content a ',' content b ']); way ('. zippy__content '). tohaveExacttext (' content '); weals ('. Zippy__content '). tohaveExacttext ([' content a ',', ',', ',', ',', '. Содержимое B ']); ожидаете ('. Zippy__content '). ) .tohavevalue ('value'); weals ('.. Zippy__content'). TocontainValue ('value'); // Примечание это ищет несколько элементов с классом и проверяет значение каждого элемента массива по индексу элемента sudedExpect ('.zippy__content'). tohavevalue (['value a', 'value b']); way ('. Zippy__content'). tocontainValue (['value a', 'value b']); ожидаете (Spectator.element ) .tohavestyle ({founalcolor: 'rgba (0, 0, 0, 0.1)'}); ожидаете ('. .checkbox '). TobeChecked (); weals ('.. Facebox '). TobeIndeterMinate (); ожидаете ('. Кнопка '). tobedisabled (); ожидайте (' div '). tobeempty (); ожидаете (' div ') .tobehidden (); weals ('element'). Tobeselected (); // Обратите внимание, что из -за ограничений в Jest (не применяя фактическую логику макета в виртуальном DOM), определенные совпадения могут привести к ложным положительным. Например, ширина и высота установлены на 0Expect ('element'). Tobevisible (); way ('input'). Tobefocused (); ожидаете ('div'). Tobemathedby ('. JS-Something'); ожидайте (зритель. component.object) .tobepartial ({Aproperty: 'avalue'}); ожидаете ('div'). tohavedescenden 'текст'});
Создать компонент, обслуживание и директиву с шаблонами спецификации зрителей с угловым CLI: (при использовании в качестве по умолчанию)
Компонент
Спецификация по умолчанию: ng g cs dashrized-name
Спецификация с хостом: ng g cs dashrized-name --withHost=true
Спецификация с пользовательским хостом: ng g cs dashrized-name --withCustomHost=true
Услуга:
Спецификация по умолчанию: ng g ss dashrized-name
Спецификация для тестирования HTTP Data Service: ng g ss dashrized-name --isDataService=true
Директива:
ng g ds dashrized-name
Чтобы использовать spectator
в качестве коллекции по умолчанию в вашем проекте Angular CLI, добавьте его в свой angular.json
:
ng config cli.defaultcollection @ngneat/spectator
Схема spectator
расширяет сборку по умолчанию @schematics/angular
. Если вы хотите установить значения по умолчанию для схем, таких как генерация компонентов с файлом SCSS, вы должны изменить имя пакета схемы с @schematics/angular
на @ngneat/spectator
in angular.json
:
"Схема": {"@ngneat/Spectator: Spectator-Component": {"стиль": "scss" } }
Примеры в карме из Angular Docs Testing Guide Developer были воспроизведены в Spectator и Jest. (Для удобства это местная версия примеров кармы.)
Здесь можно получить версию Spectator & Jest.
Netanel Basal | Дирк Луйк | Бен Эллиотт |
Спасибо этим замечательным людям (ключ смайликов): ~~~~
I. Синай ? ? | Валентин Бурьяков ? | Бен Гринхаус ? | Martin Nuc | Lars Gyrup Brink Nielsen ? | Эндрю Греков ? | ДЖЕРОН ЦВАРТЕПОРТ |
Оливер Шлегель | Rex ye ? | Чмура | Yoeri Nijs | Андерс Скарби | Грегор Войводе | Александр Шереметев ? |
Майк | Мехмет Эрим | Бретт Экерт | Исмаил Файзи | Максим | Джонатан Боннефой | Колумский паром |
Крис Купер | Марк Шейб | Dgsmith2 | Dedwardstech ? | Тамасфолди ? | Паоло Калеффи | Тони Виллена |
ИСПОЛЬЗОВАТЬ | Гийом де Джабрун | Ананд Тивари | Эльс Доганок | Золтан | Vitalii Baziuk | Clementlemarc-Certua |
Юрий Грунин | Андрей Чалкин | Стивен Харрис | Ричард Сахракорпи | Доминик Кремер | Мехмет Озан Турхан | Влад Лашко |
Уильям Тхондросухарто | Чаз Гатиан | Павел Коробов | Эноно Ломанн | Павел факуславский | Tobias Wittwer | Матео Тибакира |
Этот проект следует за спецификацией всех контролей. Взносы любого вида приветствуются!