【问题标题】:Mat Table - renderRows Unit Testing errorMat Table - renderRows 单元测试错误
【发布时间】:2020-10-05 05:15:49
【问题描述】:

我在组件中使用 mat 表,并在更新表后调用 renderRows,效果很好。 但是,在我的单元测试中,我遇到了以下错误。

在 afterAll 中抛出了一个错误 失败:无法读取未定义的属性“renderRows” 错误属性:对象({ longStack:'TypeError:无法读取未定义的属性'renderRows' 在 SafeSubscriber._next (http://localhost:9876/karma_webpack/src/app/product-management/tax-configuration/tax-configuration.component.ts:80:23)

spec.ts 文件 ->

import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { TaxConfigurationComponent } from './tax-configuration.component';
import { MatTableModule } from '@angular/material/table';
import { MatFormFieldModule } from '@angular/material/form-field';
import { MatInputModule } from '@angular/material/input';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { HttpClientTestingModule } from '@angular/common/http/testing';
import { NotificationService } from 'src/app/services/custom/notification.service';
import { TaxConfigurationService } from 'src/app/services/products/tax-configuration.service';
import { MockTaxConfigurationService } from 'src/app/services/products/tax-configuration.service.mock.spec';
import { throwError } from 'rxjs';
import { MatButtonModule } from '@angular/material/button';

describe('TaxConfigurationComponent', () => {
    let component: TaxConfigurationComponent;
    let fixture: ComponentFixture<TaxConfigurationComponent>;
    let _notificationService: NotificationService;
    let _taxService: TaxConfigurationService;

    beforeEach(async(() => {
        TestBed.configureTestingModule({
            declarations: [TaxConfigurationComponent],
            imports: [
                BrowserAnimationsModule,
                MatTableModule,
                MatFormFieldModule,
                MatInputModule,
                FormsModule,
                ReactiveFormsModule,
                HttpClientTestingModule,
                MatButtonModule,
            ],
            providers: [{ provide: TaxConfigurationService, useClass: MockTaxConfigurationService }],
        }).compileComponents();
    }));

    beforeEach(() => {
        fixture = TestBed.createComponent(TaxConfigurationComponent);
        component = fixture.componentInstance;
        fixture.detectChanges();
        _taxService = TestBed.inject(TaxConfigurationService);
        _notificationService = TestBed.inject(NotificationService);
    });

    it('should create', () => {
        expect(component).toBeTruthy();
    });

    it('should populate tax table on init', () => {
        expect(component.dataSource.length).toBeGreaterThan(0);
    });

    it('should show an error notification when "getTaxConfig()" errors out', () => {
        spyOn(_notificationService, 'startNotification').and.callThrough();
        spyOn(_taxService, 'getTaxConfig').and.returnValue(throwError('Error'));
        component.ngOnInit();
        expect(_notificationService.startNotification).toHaveBeenCalledWith(
            'An error occurred while fetching data.',
            'nc-notification--error',
            'priority_high'
        );
    });
});

component.ts 文件 ->

ngOnInit(): void {
        this.state = true;
        this.taxForm = new FormGroup({});
        this.populateTaxConfigTable();
    }

    populateTaxConfigTable(): void {
        this._taxService.getTaxConfig().subscribe((results) => {
            results.forEach((result) => {
                const rowEntry = {
                    name: result.resourceName,
                    category: result.resourceCategory,
                    id: result.resourceId,
                    tsc: new FormControl(result.taxTsc, [
                        Validators.required,
                        Validators.pattern(regexPattern),
                        Validators.max(100),
                        Validators.min(0),
                    ]),
                    ot: new FormControl(result.taxOt, [
                        Validators.required,
                        Validators.pattern(regexPattern),
                        Validators.max(100),
                        Validators.min(0),
                    ]),
                    vat: new FormControl(result.taxVat, [
                        Validators.required,
                        Validators.pattern(regexPattern),
                        Validators.max(100),
                        Validators.min(0),
                    ]),
                };
                const tscControlName = rowEntry.id + 'tsc';
                const otControlName = rowEntry.id + 'ot';
                const vatControlName = rowEntry.id + 'vat';
                this.taxForm.addControl(tscControlName, rowEntry.tsc);
                this.taxForm.addControl(otControlName, rowEntry.ot);
                this.taxForm.addControl(vatControlName, rowEntry.vat);
                this.dataSource.push(rowEntry);
            });
            this.table.renderRows();
            this.state = false;
        }, (error) => {
            this._notificationService.startNotification('An error occurred while fetching data.',
            'nc-notification--error', 'priority_high');
        });
    }

当我评论this.table.renderRows 时,单元测试正在运行,没有任何问题。对这里的问题有任何想法吗?

编辑:

模拟税配置服务

export class MockTaxConfigurationService {
    getTaxConfig(): Observable<ResourceTaxes[]> {
        return of([mockResourceTaxes, mockResourceTaxes]);
    }

    updateTaxConfig(data: TaxPostData[]): Observable<TaxResponseData[]> {
        return of([mockTaxResponseData]);
    }
}

使用 viewChild ->

export class TaxConfigurationComponent implements OnInit {
    @ViewChild(MatTable) table: MatTable<any>;
    displayedColumns: string[] = ['name', 'tsc', 'ot', 'vat'];
    taxForm: FormGroup;
    dataSource: TaxTableData[] = [];
    state = false; // Loading state
    shouldDisableSave = false;

    constructor(
        private _notificationService: NotificationService,
        private _taxService: TaxConfigurationService) {}

    ngOnInit(): void {
        this.state = true;
        this.taxForm = new FormGroup({});
        this.populateTaxConfigTable();
    }

   ...
}

【问题讨论】:

  • 您能否分享一下您的表格在组件内部是如何定义的以及模拟税务配置服务?
  • 嗨@Erbsenkoenig,请参阅更新的部分。

标签: angular unit-testing karma-jasmine mat-table


【解决方案1】:

我认为您的单元测试实际上揭示了一个您没有遇到的问题,因为您的实际税务配置服务花费了足够长的时间,直到表格被实际初始化。

onInit 中没有子视图。它在生命周期的后期设置。为此,您需要使用 ngAfterViewInit

看看here

错误显示在您的测试中,因为您的beforeEach 中的第一个fixture.detectChanges() 触发了ngOnInit。您的税务服务模拟会立即发出您的模拟值,因为 ViewChild 直到 ngAfterViewInit 才初始化,您的表仍然是 undefined

【讨论】:

    猜你喜欢
    • 2020-02-07
    • 2021-11-27
    • 2014-10-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-11-02
    • 2020-03-24
    相关资源
    最近更新 更多