директива не принята в объявлениях испытательного стенда из-за ошибки «Angular Dependency Injection» - PullRequest
0 голосов
/ 21 апреля 2020

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()
  })
})

1 Ответ

0 голосов
/ 23 апреля 2020

Оказывается, мне пришлось сделать пару вещей.

Была определенная настройка, которая была мне нужна для тестового стенда, которая была сделана для меня в библиотеке npm jest-preset- angular .. Инструкции, предоставленные там на github, однако, не дали мне работать над проектом. Поскольку ранее я вручную настраивал без этого (на основе документов из самого jest), я согласовал свой проект с этим руководством , чтобы снова получить рабочие тесты. К сожалению, это резко замедляет тестирование до такой степени, что я думаю, что карма теперь шутит от шутки и быстрее при повторных запусках. Но эй, это работает:)

В тесте большое изменение заключается в том, чтобы вручную отправлять событие, а не просто запускать обработчик события,

import { ComponentFixture, TestBed } from '@angular/core/testing'
import { By } from '@angular/platform-browser'
import { ElementRef, Component, DebugElement } from '@angular/core'

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 = false
}

describe('ClickOutsideDirective', () => {
  let fixture: ComponentFixture<MockClickOutsideComponent>
  let component: MockClickOutsideComponent
  let insideEl: DebugElement
  let innerChildEl: DebugElement
  let outsideEl: DebugElement
  let syntheticEvent: MouseEvent

  beforeEach(() => {
    TestBed.configureTestingModule({
      declarations: [MockClickOutsideComponent, ClickOutsideDirective]
    }).compileComponents()
    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'))

    syntheticEvent = new MouseEvent('click', {
      view: window,
      bubbles: true,
      cancelable: true
    })
  })

  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.nativeElement.dispatchEvent(syntheticEvent)
    fixture.detectChanges()

    expect(component.directiveDidFire).toBeTruthy()
  })

  it('should not emit on click inside', () => {
    insideEl.nativeElement.dispatchEvent(syntheticEvent)
    fixture.detectChanges()

    expect(component.directiveDidFire).toBeFalsy()
  })

  it('should not emit on click of child of inside element', () => {
    innerChildEl.nativeElement.dispatchEvent(syntheticEvent)
    fixture.detectChanges()

    expect(component.directiveDidFire).toBeFalsy()
  })
})
...