update
, изучая это немного дольше, оказалось, что первоначальная ошибка была из-за отсутствия BrowserDynamicTestingModule в моей настройке шутки. Есть также способы передачи фиктивного ElementRef в качестве провайдера, чтобы избавиться от ошибка. Однако выполнение любого из них не приводит к тому, что тест действительно работает. Я создал новый проект, в котором ничего не было добавлено, кроме этой директивы, поэтому он не в шутку, и все же я не могу получить проходной набор тестов.
-
По какой-то причине, когда Я добавляю свою директиву к объявлениям на испытательном стенде, получаю:
This constructor is not compatible with Angular Dependency Injection because its dependency at index 0 of the parameter list is invalid.
This can happen if the dependency type is a primitive like a string or if an ancestor of this class is missing an Angular decorator.
Please check that 1) the type for the parameter at index 0 is correct and 2) the correct Angular decorators are defined for this class and its ancestors
Мне бы хотелось, чтобы эта директива и spe c работали
Директива
import {
Directive,
ElementRef,
Output,
EventEmitter,
HostListener
} from '@angular/core'
@Directive({
selector: '[common-click-outside]'
})
export class ClickOutsideDirective {
@Output('common-click-outside') clickOutsideEmitter: EventEmitter<
any
> = new EventEmitter()
constructor (private _elementRef: ElementRef) {}
@HostListener('document:click', ['$event.target']) onClick (
targetElement: ElementRef
) {
const isClickedInside = this._elementRef.nativeElement.contains(
targetElement
)
if (!isClickedInside) this.clickOutsideEmitter.next()
}
}
spe c
import { ElementRef, Component, DebugElement } from '@angular/core'
import { ComponentFixture, TestBed } from '@angular/core/testing'
import { By } from '@angular/platform-browser'
import { ClickOutsideDirective } from './click-outside.directive'
@Component({
template: `
<div class="parent">
<div class="inside" (common-click-outside)="directiveDidFire = true">
<span class="inner-child"></span>
</div>
<div class="outside"></div>
</div>
`
})
class MockClickOutsideComponent {
directiveDidFire: boolean
}
describe('ClickOutsideDirective', () => {
let fixture: ComponentFixture<MockClickOutsideComponent>
let component: MockClickOutsideComponent
let insideEl: DebugElement
let innerChildEl: DebugElement
let outsideEl: DebugElement
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [MockClickOutsideComponent, ClickOutsideDirective]
})
fixture = TestBed.createComponent(MockClickOutsideComponent)
component = fixture.componentInstance
insideEl = fixture.debugElement.query(By.css('.inside'))
innerChildEl = fixture.debugElement.query(By.css('.inner-child'))
outsideEl = fixture.debugElement.query(By.css('.outside'))
})
it('should create an instance', () => {
const insideEl = document.createElement('div')
const insideElRef = new ElementRef<HTMLElement>(insideEl)
const directive = new ClickOutsideDirective(insideElRef)
expect(directive).toBeDefined()
})
it('should emit on click outside', () => {
outsideEl.triggerEventHandler('click', null)
fixture.detectChanges()
expect(component.directiveDidFire).toBeTruthy()
})
it('should not emit on click inside', () => {
insideEl.triggerEventHandler('click', null)
fixture.detectChanges()
expect(component.directiveDidFire).toBeFalsy()
})
it('should not emit on click of child of inside element', () => {
innerChildEl.triggerEventHandler('click', null)
fixture.detectChanges()
expect(component.directiveDidFire).toBeFalsy()
})
})