【问题标题】:directive not accepted in testbed declarations due to "Angular Dependency Injection" error由于“Angular Dependency Injection”错误,测试平台声明中不接受指令
【发布时间】:2020-08-04 06:08:17
【问题描述】:

更新

再看久一点,原来最初的错误是因为在我的笑话设置中缺少 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

我希望这个指令和规范起作用

指令

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

规格

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

【问题讨论】:

    标签: angular jestjs angular9


    【解决方案1】:

    事实证明我必须做几件事。

    我需要在 npm 库 jest-preset-angular 中为我完成的测试台进行一些设置。然而,在 github 上提供的说明并没有让项目为我工作。由于我之前在没有这个的情况下手动设置(基于 jest 本身的文档),所以我使我的项目符合这个 guide 以再次进行工作测试。不幸的是,这戏剧性地减慢了测试速度,以至于我认为业力现在与开玩笑并驾齐驱,并且在重新运行时更快。但是,嘿,它有效:)

    在测试中,最大的变化是手动分发事件而不是仅仅触发事件处理程序,

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-11-21
      • 1970-01-01
      • 2019-12-24
      • 1970-01-01
      • 2015-07-08
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多