我正在使用 Karma 和 jasmine 對我的組件進行單元測驗。fixture.detechChanges() 應該用于每個測驗以檢測更改。但是這種方法使測驗用例失敗并給出錯誤
錯誤:InvalidPipeArgument:“無法將“無效日期”轉換為管道“DatePipe”的日期
由于我是新手,任何人都可以讓我知道為什么會這樣,以及使用它的正確位置是什么。
在三個測驗用例中,第二個測驗用例失敗了。我做了很多研究,但我不確定為什么我的測驗用例失敗了。
下面是我的代碼
資源概述.component.ts
import { ResourceOverviewService } from '../../../../services/detail/resource-overview/resource-overview.service'
import {
Component,
OnInit,
} from '@angular/core';
import { UtilsService } from '../../../../services/common/utils.service';
import { Router, ActivatedRoute } from '@angular/router';
@Component({
selector: 'app-resource-overview',
templateUrl: './resource-overview.component.html',
styleUrls: ['./resource-overview.component.scss']
})
export class ResourceOverviewComponent implements OnInit {
uuid = '--';
resourceName = '--';
status = '--';
provider = '--';
providerAccount = '--';
resourceCategory = '--';
resourceType = '--';
region = '--';
overviewTags = '--';
correlationID = '--';
showMore = true;
crn = '--'
lastupdated : any;
providerAccountName = '--'
resourceId = '--'
creationDate = '--'
description = '--'
tags = '--'
dateTimeFormat = 'MMM d, y h:mm a';
lastUpdateTime: any;
dateTimeZone: any;
keyValue : { key: any, value: any }[] = [];
id = '--';
providerLastUpdated = '--';
providerStatus = '--';
breadcrumbs = [];
launchpadURL = `/launchpad`;
constructor(
private readonly resourceOverviewService: ResourceOverviewService,
private readonly utilsService: UtilsService,
private readonly router: Router,
readonly route: ActivatedRoute,
) {}
ngOnInit() {
this.id = this.route.snapshot.queryParamMap.get('id');
this.getDetails();
// this.route.queryParams.subscribe(params => {
// console.log("---", params)
// this.id = params.id
// this.getDetails();
// })
}
viewInventory(){
this.router.navigate(['..'], {
relativeTo: this.route
});
}
getDetails() {
if (this.id) {
this.getResourceOverview();
}
}
getResourceOverview(): void {
const resourceID = `search_keys=${"resource_id"}&search=${this.id}`
this.resourceId = this.id
this.resourceOverviewService
.getResourceOverview(resourceID)
.subscribe(
(response) => {
const result = response as any;
if (result && result.raw_items[0]) {
this.uuid = result.raw_items[0].uuid || '--';
this.resourceName = result.raw_items[0].gpd.provider_resource_name || '--';
this.status = result.raw_items[0].gpd.status || '--';
this.provider = result.raw_items[0].gpd.provider_code || '--';
this.providerAccountName = result.raw_items[0].gpd.provider_account_name || '--';
this.providerAccount = result.raw_items[0].gpd.provider_account || '--';
this.resourceCategory = result.raw_items[0].gpd.service_category || '--';
this.resourceType = result.raw_items[0].gpd.provider_resource_type || '--';
this.region = result.raw_items[0].gpd.provider_resource_location || '--';
this.keyValue = result.raw_items[0].gpd.tags;
this.crn = result.raw_items[0].gpd.provider_resource_crn || '--';
this.lastupdated = new Date(Date.parse(result.raw_items[0].gpd.discovery_lastupdated)) || '--' ;
this.providerLastUpdated = result.raw_items[0].gpd.provider_resource_lastupdated || '--' ;
this.dateTimeZone = this.utilsService.getLocalBrowserTime(this.lastupdated) || '--' ;
this.dateTimeFormat = this.utilsService.getDateTimeFormat() || '--' ;
this.creationDate = result.raw_items[0].gpd.provider_resource_created || '--' ;
this.correlationID = result.raw_items[0].gpd.correlation_id || '--' ;
this.providerStatus = result.raw_items[0].gpd.provider_status || '--' ;
}
},
(error) => {
console.log('Resource overview details failed with error', error);
}
);
}
}
資源概述.component.spec.ts
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { HttpWrapperService } from '../../../../services/common/http-wrapper.service';
import { ResourceOverviewComponent } from './resource-overview.component';
import { NGXLogger } from 'ngx-logger';
import { HttpClientTestingModule } from '@angular/common/http/testing';
import { CarbonComponentsModule } from '@cloudMatrix-CAM/cb-carbon-components-lib';
import { CarbonModule } from '../../../../../carbon.module';
import { ApiContractService, CbTranslationUiLibModule, TranslationService,AuthenticationContractService } from '@cloudMatrix-CAM/cb-common-ui';
import { MockNGXLogger } from '../../../../components/discovery-inventory/list-view/list-view.component.spec';
import { convertToParamMap, Router } from '@angular/router';
import { ApiService } from '../../../../services/common/api.service';
import { CUSTOM_ELEMENTS_SCHEMA, DebugElement } from '@angular/core';
import { CbCommonDiscoveryManagementMicroUiService } from '../../../../services/cb-common-discovery-management-micro-ui.service';
import { ActivatedRoute } from "@angular/router";
import { throwError, of, Observable } from 'rxjs';
import { RouterModule } from '@angular/router'
import { ResourceOverviewService } from 'projects/cb-common-discovery-management-micro-ui/src/app/services/detail/resource-overview/resource-overview.service';
class mockHttpWrapperService {
readonly isApiReady = false;
}
describe('ResourceOverviewComponent', () => {
let component: ResourceOverviewComponent;
let fixture: ComponentFixture<ResourceOverviewComponent>;
let resourceOverviewService: any;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ ResourceOverviewComponent ],
imports: [
CarbonComponentsModule,CarbonModule,CbTranslationUiLibModule.forRoot(),
RouterModule.forRoot([]),
],
providers: [
{ provide: NGXLogger, useClass: MockNGXLogger },
{ provide: HttpWrapperService, useClass: mockHttpWrapperService },
{ provide: Router, useClass: class { navigate = jasmine.createSpy("navigate"); }},
ApiService,
ApiContractService,
ResourceOverviewService,
TranslationService,
CbCommonDiscoveryManagementMicroUiService,
{
provide: ActivatedRoute,
useValue: {
params: of({ id: 'aeb24ca0549c', code: 'IBM' }),
snapshot: {
queryParamMap: convertToParamMap({
id: 'aeb24ca0549c',
code: 'IBM',
})
}
}
},
],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
})
.compileComponents()
}));
beforeEach(() => {
fixture = TestBed.createComponent(ResourceOverviewComponent);
component = fixture.debugElement.componentInstance;
// fixture.detectChanges();
});
it('should create component ', () => {
expect(component).toBeTruthy();
});
it('should init object for action tabs', async () => {
await fixture.whenStable();
component.ngOnInit();
fixture.detectChanges();
expect(component).toBeTruthy();
});
it('should get resource data ', () => {
resourceOverviewService = TestBed.inject(ResourceOverviewService);
const data = {"raw_items":[{"uuid":"123456789:i-0105345f167219fbf:vms","gpd":{"version":"0.1","discovery_lastupdated":"2021-09-08T05:36:08Z","correlation_id":"aws-123456789-i-0105345f167219fbf","core_credential_id":["credid"],"provider_code":"aws","provider_account":"123456789","provider_account_name":"accountname","provider_account_details":{"cb84865d-3477-40f3-9131-4462273cfedb":"accountname"},"provider_resource_type":"vms","provider_resource_id":"i-0105345f167219fbf","provider_resource_name":"cd-642","provider_resource_lastupdated":"","provider_resource_created":"2021-08-30T06:12:49Z","provider_resource_crn":"arn:aws:ec2:us-east-1:123456789:vms/i-0105345f167219fbf","provider_resource_location":"us-east-1","provider_status":"running","location_geo_coordinates":{"latitude":38.86726,"longitude":-77.233959},"status":"Active","service_category":"compute","tags":[{"Key":"Name","Value":"cd-642"}],"raw_config_data":null,"extended_data":null}}],"meta":null,"pagination":{"count":1,"total":1,"offset":0,"limit":10,"first":"https://local-core.gravitant.net/discovery/api/inventory/v1/service?limit=10","last":"https://local-core.gravitant.net/discovery/api/inventory/v1/service?limit=10","next":"","prev":""}};
spyOn(resourceOverviewService, "getResourceOverview").and.callFake(() => {
return of(data)
})
component.getDetails();
fixture.detectChanges();
expect(component).toBeTruthy();
});
});
資源概述.component.html
<div >
<div >
<ibm-breadcrumb>
<ibm-breadcrumb-item href="{{launchpadURL}}">
Portal
</ibm-breadcrumb-item>
<ibm-breadcrumb-item >
<a (click)="viewInventory()">Inventory Resource view</a>
</ibm-breadcrumb-item>
<ibm-breadcrumb-item >
{{ id }}
</ibm-breadcrumb-item>
</ibm-breadcrumb>
<div >
<label >{{ id }}</label>
</div>
<div>
<label >{{ 'discovery_inventory.resource_overview.discovery_lastupdated' | translate }}
{{lastupdated | date : dateTimeFormat}} {{dateTimeZone}}</label>
</div>
</div>
<div >
<div >
<label >{{"discovery_inventory.resource_overview.overview" | translate}}</label>
</div>
<div >
<div >
<div >
<div >
<label >{{"discovery_inventory.resource_overview.id" | translate}}</label>
<span
title="{{ id }}"
>{{ id }}</span
>
</div>
</div>
<div >
<div >
<label >{{"discovery_inventory.resource_overview.resource_type" | translate}}</label>
<span
title="{{ resourceType }}"
>{{ resourceType }}</span
>
</div>
</div>
</div>
<div >
<div >
<div >
<label >{{
"discovery_inventory.resource_overview.region" | translate
}}</label>
<span
title="{{ region }}"
>{{ region }}</span
>
</div>
</div>
<div >
<div >
<label >{{
"discovery_inventory.resource_overview.tag_key_value" | translate
}}</label>
<div *ngFor="let k of keyValue; let i = index;">
<span *ngIf="i!=(keyValue.length-1)"
title="{{ id }}"
>{{ k.Key }} : {{ k.Value }} ,
</span>
<span *ngIf="i==(keyValue.length-1)"
title="{{ id }}"
>{{ k.Key }}:{{ k.Value }}
</span>
</div>
</div>
</div>
</div>
<div >
<div >
<div >
<label >{{
"discovery_inventory.resource_overview.correlation_id" | translate
}}</label>
<span
title="{{ correlationID }}"
>{{ correlationID }}</span
>
</div>
</div>
<div >
<div >
<label >{{
"discovery_inventory.resource_overview.resource_category" | translate
}}</label>
<span
title="{{ resourceCategory }}"
>{{ resourceCategory }}</span
>
</div>
</div>
</div>
<div *ngIf="showMore">
<div >
<div >
<div >
<label >{{
"discovery_inventory.resource_overview.status" | translate
}}</label>
<span
title="{{ status }}"
>{{ status }}</span
>
</div>
</div>
<div >
<div >
<label >{{
"discovery_inventory.resource_overview.provider" | translate
}}</label>
<span
title="{{ provider }}"
>{{ provider }}</span
>
</div>
</div>
</div>
<div >
<div >
<div >
<label >{{
"discovery_inventory.resource_overview.provider_account" | translate
}}</label>
<span
title="{{ providerAccount }}"
>{{ providerAccount }}</span
>
</div>
</div>
<div >
<div >
<label >{{
"discovery_inventory.resource_overview.resource_name" | translate
}}</label>
<span
title="{{ resourceName }}"
>{{ resourceName }}</span
>
</div>
</div>
</div>
</div>
<div >
<div (click)="showMore = !showMore">
<label *ngIf="showMore">{{
"discovery_inventory.resource_overview.show_less" | translate
}}</label>
<label *ngIf="!showMore">{{
"discovery_inventory.resource_overview.show_more" | translate
}}</label>
</div>
</div>
</div>
</div>
<div >
<div >
<label >{{"discovery_inventory.resource_overview.configuration_details" | translate}}</label>
</div>
<div >
<div >
<div >
<div >
<label >{{"discovery_inventory.resource_overview.account_id" | translate}}</label>
<span
title="{{ providerAccount }}"
>{{ providerAccount }}</span
>
</div>
</div>
<div >
<div >
<label >{{
"discovery_inventory.resource_overview.provider_account_name" | translate
}}</label>
<span
title="{{ providerAccount }}"
>{{ providerAccountName }}</span
>
</div>
</div>
</div>
<div >
<div >
<div >
<label >{{"discovery_inventory.resource_overview.creation_date" | translate}}</label>
<span
title="{{ creationDate }}"
>{{ creationDate }}</span
>
</div>
</div>
<div >
<div >
<label >{{
"discovery_inventory.resource_overview.provider_lastupdated" | translate
}}</label>
<span
title="{{ providerLastUpdated }}"
>{{ providerLastUpdated }}</span
>
</div>
</div>
</div>
<div >
<div >
<div >
<label >{{
"discovery_inventory.resource_overview.arn" | translate
}}</label>
<span
title="{{ crn }}"
>{{ crn }}</span
>
</div>
</div>
<div >
<div >
<label >{{"discovery_inventory.resource_overview.provider_status" | translate}}</label>
<span
title="{{ providerStatus }}"
>{{ providerStatus }}</span
>
</div>
</div>
</div>
<div >
<div >
<div >
<label >{{"discovery_inventory.resource_overview.tags" | translate}}</label>
<div>
<span >
<table>
<tr>
<th>Key</th>
<th>Value</th>
</tr>
<tr *ngFor="let k of keyValue; let i = index;">
<td>{{k.Key}}</td>
<td>{{k.Value}}</td>
</tr>
</table>
</span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
uj5u.com熱心網友回復:
第二次測驗
您正在呼叫 component.ngOnInit(); 內部呼叫 getDetails();
第三次測驗
您正在呼叫 getDetails();
IMO,兩者都在做相同的事情,要么您可以洗掉第二個測驗并讓您的第三個測驗呼叫 component.ngOnInit(); 使用模擬 api 回應或在第二個測驗中具有相同的模擬 API 回應。
uj5u.com熱心網友回復:
問題
問題是您的測驗正在構建并為 angular 提供無效日期DatePipe。由于管道存在于您的 HTML 中,因此您只會在運行后看到錯誤,detectChanges因為模板僅在那時才呈現。
錯誤發生在你lastUpdated | date:dateTimeFormat這里
<label >{{ 'discovery_inventory.resource_overview.discovery_lastupdated' | translate }}
{{lastupdated | date : dateTimeFormat}} {{dateTimeZone}}</label>
由于您getResourceOverview在測驗中執行(由于設定了 ID),因此還將執行以下行:
// This will construct an invalid date, since date is always truthy (even when called with "new Date(undefined)",
// "|| '--'" will never be executed
this.lastupdated = new Date(Date.parse(result.raw_items[0].gpd.discovery_lastupdated)) || '--' ;
這有效地將無效日期(由 構造new Date(undefined))分配給您的lastupdated實體變數,從而導致您看到的錯誤。
解決方案
您要么必須確保在測驗中提供所有必要的資料和/或使您的代碼更加健壯。在這種情況下,我強烈建議在向管道提供資料之前正確檢查 undefined/null:
<label >
{{ 'discovery_inventory.resource_overview.discovery_lastupdated' | translate }}
<!--
Use the terniary operator to conditionally use the pipe or fall back
to "--" ("--" itself would be an invalid argument for the pipe, so do
not provide this to the pipe directly!)
-->
{{ (lastupdated ? (lastupdated | date : dateTimeFormat) : '--' }} {{dateTimeZone}}
</label>
此外,如果您無法為變數構造有效日期,則應確保分配 undefined:
this.lastupdated = result.raw_items[0].gpd.discovery_lastupdated
? new Date(Date.parse(result.raw_items[0].gpd.discovery_lastupdated))
: undefined ;
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/352507.html
