Angular 2+ Unitest 提供带有窗口注入(inject)对象的指令

标签 angular typescript testing angular2-directives

我正在尝试为一个指令编写一个测试,该指令在其构造函数中接收一个窗口对象

指令代码:

 import { Directive, ElementRef, Input, OnChanges, OnDestroy, OnInit } from                                             
    '@angular/core';
    import { Inject } from '@angular/core';
    import { Observable, Subscription } from 'rxjs/Rx';


    @Directive({
        selector: '[appFixToViewport]'
    })
    export class FixToViewportDirective implements OnChanges, OnDestroy, OnInit {
    @Input('appFixToViewport') appFixToViewport: boolean;
    @Input('outerMargin') outerMargin: number = 15; // defaults to 15px margin
    private windowResize$: Subscription;

    constructor(private element: ElementRef,
                @Inject('$window') private $window: any) {}

    ngOnInit() {
        this.windowResize$ = Observable.fromEvent(this.$window, 'resize')
            .debounceTime(500)
            .subscribe((event) => {
                this.fixDropdownToViewPort();
            });
    }

    ngOnChanges(changes) {
        if (changes.appFixToViewport.currentValue) {
            this.fixDropdownToViewPort();
        }
    }

    ngOnDestroy() {
        if (this.windowResize$ !== undefined) {
            this.windowResize$.unsubscribe();
        }
    }

    /**
     * Name: fixDropdownToViewPort
     * Purpose: put div element inside the view port
     * Returns: void
     */
    fixDropdownToViewPort() {
        this.$window.requestAnimationFrame(() => {
            this.element.nativeElement.style.transform = ''; // reset transform

            let winWidth = this.$window.innerWidth;
            // Attempt obtaining a more accurate width (excluding scrollbars)
            if (this.$window.document && this.$window.document.body.clientWidth) {
                winWidth = this.$window.document.body.clientWidth;
            }
            let elementWidth = this.element.nativeElement.offsetWidth; // div width

            // div right border absolute position
            let elementRight = this.element.nativeElement.getBoundingClientRect().right;

            // div left border absolute position
            let elementLeft = this.element.nativeElement.getBoundingClientRect().left;

            let delta = 0;

            if (elementRight > winWidth && winWidth > elementWidth) { // calc if the div is overflow right
                delta = elementRight - winWidth + this.outerMargin;
            }
            else if (winWidth < elementWidth) { // calc if the div is bigger then the view port
                delta = elementLeft - this.outerMargin;
            }
            this.element.nativeElement.style.transform = `translateX(${-delta}px)`;
        });
    }
}

当我尝试初始化模板中使用指令的测试组件时,我收到注入(inject)错误

这是测试规范文件:

import {Component, ElementRef, DebugElement} from '@angular/core';
import {TestBed, async, ComponentFixture} from '@angular/core/testing';
import {FixToViewportDirective} from './fixToViewport.directive';
import {createInjector} from "@angular/core/src/view/refs";
import {By} from "@angular/platform-browser";


@Component({
    selector: 'app-test-fixtoviewport',
    template:'<div appFixToViewport="isOpenFlag" ></div>'
    })
class TestFixToViewPort {}


describe('Directive: FixToViewportDirective',()=>{
    let component :TestFixToViewPort
    let fixture : ComponentFixture<TestFixToViewPort>;
    let inputEl: DebugElement;
    const $window= Window;

    beforeEach((()=>{

        TestBed.configureTestingModule({
            declarations: [
                TestFixToViewPort,
                FixToViewportDirective
            ]});

             fixture = TestBed.createComponent(TestFixToViewPort);
             component= fixture.componentInstance;
             inputEl= fixture.debugElement.query(By.css('div'));
        }));
    it('should have a defined component', () => {
        expect(component).toBeDefined();
    });
    })

和错误跟踪:

指令:FixToViewportDirective

    × should have a defined component
        Error
            at injectionError (webpack:///~/@angular/core/@angular/core.es5.js:1232:0 <- src/test.ts:1511:86) [angular]
            at noProviderError (webpack:///~/@angular/core/@angular/core.es5.js:1270:0 <- src/test.ts:1549:12) [angular]
            at ReflectiveInjector_._throwOrNull (webpack:///~/@angular/core/@angular/core.es5.js:2771:0 <- src/test.ts:3050:19) [angular]
            at ReflectiveInjector_._getByKeyDefault (webpack:///~/@angular/core/@angular/core.es5.js:2810:0 <- src/test.ts:3089:25) [angular]

        Expected undefined to be defined.
            at Object.<anonymous> (webpack:///src/app/shared/fixViewport/fixToViewportTester.component.spec.ts:42:7 <- src/test.ts:144444:27) [ProxyZone]
            at ProxyZoneSpec.onInvoke (webpack:///~/zone.js/dist/proxy.js:80:0 <- src/test.ts:114788:39) [ProxyZone]
            at Object.<anonymous> (webpack:///~/zone.js/dist/jasmine-patch.js:105:9 <- src/test.ts:114487:34) [<root>]

Chrome 59.0.3071 (Windows 10 0.0.0) Directive: FixToViewportDirective should have a defined component FAILED
        Error
            at injectionError (webpack:///~/@angular/core/@angular/core.es5.js:1232:0 <- src/test.ts:1511:86) [angular]
            at noProviderError (webpack:///~/@angular/core/@angular/core.es5.js:1270:0 <- src/test.ts:1549:12) [angular]
            at ReflectiveInjector_._throwOrNull (webpack:///~/@angular/core/@angular/core.es5.js:2771:0 <- src/test.ts:3050:19) [angular]
            at ReflectiveInjector_._getByKeyDefault (webpack:///~/@angular/core/@angular/core.es5.js:2810:0 <- src/test.ts:3089:25) [angular]
            at ReflectiveInjector_._getByKey (webpack:///~/@angular/core/@angular/core.es5.js:2742:0 <- src/test.ts:3021:25) [angular]
            at ReflectiveInjector_.get (webpack:///~/@angular/core/@angular/core.es5.js:2611:0 <- src/test.ts:2890:21) [angular]
            at DynamicTestModuleInjector.NgModuleInjector.get (webpack:///~/@angular/core/@angular/core.es5.js:3579:0 <- src/test.ts:3858:52) [angular]
            at resolveDep (webpack:///~/@angular/core/@angular/core.es5.js:11040:0 <- src/test.ts:11319:45) [angular]
            at createClass (webpack:///~/@angular/core/@angular/core.es5.js:10896:0 <- src/test.ts:11175:91) [angular]
            at createDirectiveInstance (webpack:///~/@angular/core/@angular/core.es5.js:10724:0 <- src/test.ts:11003:37) [angular]
            at createViewNodes (webpack:///~/@angular/core/@angular/core.es5.js:12087:29 <- src/test.ts:12366:49) [angular]
            at callViewAction (webpack:///~/@angular/core/@angular/core.es5.js:12531:0 <- src/test.ts:12810:13) [angular]
            at execComponentViewsAction (webpack:///~/@angular/core/@angular/core.es5.js:12440:0 <- src/test.ts:12719:13) [angular]
            at createViewNodes (webpack:///~/@angular/core/@angular/core.es5.js:12114:0 <- src/test.ts:12393:5) [angular]
        Expected undefined to be defined.
            at Object.<anonymous> (webpack:///src/app/shared/fixViewport/fixToViewportTester.component.spec.ts:42:7 <- src/test.ts:144444:27) [ProxyZone]
            at ProxyZoneSpec.onInvoke (webpack:///~/zone.js/dist/proxy.js:80:0 <- src/test.ts:114788:39) [ProxyZone]
            at Object.<anonymous> (webpack:///~/zone.js/dist/jasmine-patch.js:105:9 <- src/test.ts:114487:34) [<root>]

Chrome 59.0.3071 (Windows 10 0.0.0): Executed 1 of 1 (1 FAILED) ERROR (1.053 secs / 0.076 secs)

我如何将它搜索的窗口对象注入(inject)指令?

最佳答案

尝试将 ElementRef 添加到您的测试模块:

 TestBed.configureTestingModule({
            declarations: [
                TestFixToViewPort,
                FixToViewportDirective
            ],
            imports: [ ElementRef ]
});

关于Angular 2+ Unitest 提供带有窗口注入(inject)对象的指令,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45185747/

相关文章:

angular - 无法将 Angular 从版本 6 降级到版本 5

reactjs - react-dnd:拖出一条线

javascript - 如何在 typescript 中使用表单元素

javascript - 如何使用类验证器验证多种类型的嵌套数组?

testing - 组织.hsqldb.HsqlException : user lacks privilege or object not found: DATABASECHANGELOGLOCK

android - 移动端测试工具-> Android Native application

testing - 你如何解决一个不可重现的、随机的和变化不能立即测试的问题?

jquery - Angular - 数据表 : TypeError: Cannot read property 'nodeName' of null

angular - 来自不同脚本的多个 Angular 元素

javascript - 从枚举填充数组(Angular)