角度测试错误 - NullInjectorError:没有 TrimInputDirective 的提供者
Posted
技术标签:
【中文标题】角度测试错误 - NullInjectorError:没有 TrimInputDirective 的提供者【英文标题】:Angular Test Error - NullInjectorError: No provider for TrimInputDirective 【发布时间】:2018-11-11 08:50:10 【问题描述】:我创建了一个 Angular 指令,它使用 CSS 选择器在我的应用程序中自动修剪输入,看起来像这样......
import Directive, HostListener, forwardRef from '@angular/core';
import DefaultValueAccessor, NG_VALUE_ACCESSOR from '@angular/forms';
export const TRIM_VALUE_ACCESSOR: any =
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => TrimInputDirective),
multi: true
;
/**
* The trim accessor for writing trimmed value and listening to changes that is
* used by the @link NgModel, @link FormControlDirective, and
* @link FormControlName directives.
*/
/* tslint:disable */
@Directive(
selector: `
input
:not([type=checkbox])
:not([type=radio])
:not([type=password])
:not([readonly])
:not(.ng-trim-ignore)
[formControlName],
input
:not([type=checkbox])
:not([type=radio])
:not([type=password])
:not([readonly])
:not(.ng-trim-ignore)
[formControl],
input
:not([type=checkbox])
:not([type=radio])
:not([type=password])
:not([readonly])
:not(.ng-trim-ignore)
[ngModel],
textarea
:not([readonly])
:not(.ng-trim-ignore)
[formControlName],
textarea
:not([readonly])
:not(.ng-trim-ignore)
[formControl],
textarea
:not([readonly])
:not(.ng-trim-ignore)[ngModel],
:not([readonly])
:not(.ng-trim-ignore)
[ngDefaultControl]'
`,
providers: [ TRIM_VALUE_ACCESSOR ]
)
/* tslint:enable */
export class TrimInputDirective extends DefaultValueAccessor
protected _onTouched: any;
/**
* ngOnChange - Lifecycle hook that is called when any data-bound property of a directive changes.
* @param string val - trim value onChange.
*/
@HostListener('input', ['$event.target.value'])
public ngOnChange = (val: string) =>
this.onChange(val.trim());
/**
* applyTrim - trims the passed value
* @param string val - passed value.
*/
@HostListener('blur', ['$event.target.value'])
public applyTrim(val: string)
this.writeValue(val.trim());
this._onTouched();
/**
* writeValue - trims the passed value
* @param any value - passed value.
*/
public writeValue(value: any): void
if (typeof value === 'string')
value = value.trim();
super.writeValue(value);
/**
* registerOnTouched Registers a callback function that should be called when the control receives a blur event.
* @param function fn - The user information.
*/
public registerOnTouched(fn: any): void
this._onTouched = fn;
现在作为一名优秀的开发人员,我必须纠正一些单元测试......所以我开始将一个文件放在一起,在这里
import Component from '@angular/core';
import async, ComponentFixture, TestBed from '@angular/core/testing';
import By from '@angular/platform-browser';
import TrimInputDirective from './trim-input.directive';
import expect from 'chai';
@Component(
selector: 'my-directive-test-component',
template: ''
)
class TestComponent
describe('Trim Directive', () =>
let fixture: ComponentFixture<TestComponent>;
let inputDebugElement: any;
let directive: TrimInputDirective;
beforeEach(async(() =>
TestBed.configureTestingModule(
declarations: [
TestComponent,
TrimInputDirective
],
providers: []
).overrideComponent(TestComponent,
set:
template: '<input type="text">'
).compileComponents().then(() =>
fixture = TestBed.createComponent(TestComponent);
fixture.detectChanges();
inputDebugElement = fixture.debugElement.query(By.css('input'));
directive = inputDebugElement.injector.get(TrimInputDirective);
);
));
it('should trim the input', () =>
directive.ngOnChange(' 1234.56 ')
expect('1234.56').to.be('1234.56'); // I know this isn't the correct test... I will amend this
);
);
现在我希望运行我的测试只是为了确保规范文件中的设置正确,但我收到以下错误:
HeadlessChrome 0.0.0 (Mac OS X 10.12.6) Trim Directive “before each” “应该修剪输入”的钩子失败未捕获(承诺):错误: StaticInjectorError(DynamicTestModule)[TrimInputDirective]: StaticInjectorError(平台:核心)[TrimInputDirective]: NullInjectorError:没有 TrimInputDirective 的提供者!错误:StaticInjectorError(DynamicTestModule)[TrimInputDirective]:
我不明白为什么会出现这个错误,为什么我必须提供指令?我不认为这是必要的,如果我必须提供我应该提供什么?提供实际指令不起作用/解决错误?我很迷茫。如果有人能告诉我如何解决这个问题或为什么我会得到它,我将不胜感激。
请注意,这是一个旧版 Angular 应用程序,并且是在 AngularCLI 可用。所以它有点不正统(例如它没有使用 Jasmin)。
【问题讨论】:
【参考方案1】:您必须在 TestComponent
中提供类似这样的指令
@Component(
selector: 'my-directive-test-component',
template: '',
providers: [ TrimInputDirective ]
)
class TestComponent
【讨论】:
我试过了,然后我被要求提供更多的供应商,这自然是我尝试的第一件事。我认为我的实现有问题 指令应声明为未提供。 angular.io/guide/…【参考方案2】:1) 你不需要提供你的指令,你只需要在TestingModule
中声明它。然后,它将在模板中与相应的选择器一起使用。
2) 您的选择器与输入中使用的选择器不对应。如果您希望将 formControlName
应用于某些类型的所有输入或更改您的测试,请删除它。
input
:not([type=checkbox])
:not([type=radio])
:not([type=password])
:not([readonly])
:not(.ng-trim-ignore)
[formControlName],
^^^^^^^^^^^^^^^^^^
3) 指令会在某些事件上触发。您需要模拟这些事件才能看到效果。看看这个简化的例子。 (Stackblitz)
@Directive(
selector: `
input
:not([type=checkbox])
:not([type=radio])
:not([type=password])
:not([readonly])
:not(.ng-trim-ignore)
`
)
export class TrimInputDirective
constructor(private el: ElementRef)
@HostListener('blur') onLeave()
if (this.el.nativeElement.value)
this.el.nativeElement.value = this.el.nativeElement.value.trim();
还有测试:
describe('Trim Directive', () =>
let fixture: ComponentFixture<TestComponent>;
let inputDebugElement: any;
let directive: TrimInputDirective;
beforeEach(async(() =>
TestBed.configureTestingModule(
declarations: [
TestComponent,
TrimInputDirective
],
imports: [FormsModule],
providers: []
).overrideComponent(TestComponent,
set:
template: '<input type="text">'
).compileComponents().then(() =>
fixture = TestBed.createComponent(TestComponent);
inputDebugElement = fixture.debugElement.query(By.css('input')).nativeElement;
^^^^^^^^^^^^
);
));
it('should trim the input', () =>
inputDebugElement.value = ' 1234.56 ';
inputDebugElement.dispatchEvent(new Event('blur'));
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
fixture.detectChanges();
expect(inputDebugElement.value).toBe('1234.56');
);
);
【讨论】:
以上是关于角度测试错误 - NullInjectorError:没有 TrimInputDirective 的提供者的主要内容,如果未能解决你的问题,请参考以下文章
获取错误:在角度 js 中进行单元测试时出现 $injector:modulerr 模块错误
正则表达式测试作为属性的指令实现错误 - 验证(打字稿+角度)