我对Angular组件进行了一些更新,但它破坏了一些单元测试。所有测试规范均已损坏,因此对我来说似乎与beforeEach
调用中的初始化有关。我已经尝试过广泛研究该问题,但是没有取得任何成功。
我从运行单元测试中得到的错误是:
TypeError: Cannot read property 'subscribe' of undefined
对subscribe
的唯一呼叫是:
this.ruleDataFieldOption$.subscribe
...
this.submitted$.subscribe
...
this.dataFieldControl.valueChanges.subscribe
我试图通过将ruleDataFieldOption$
设置为of(mockRuleDataFields)
来显式地初始化beforeEach
,但这没用。我还尝试将代码块从第二个beforeEach
调用移到异步.compileComponents().then( () => {...} )
调用的承诺中(即const mockDataFieldService = {
getRuleDataFields: () => {}
} as RuleDataFieldService;
const mockStore = {
select: td.function('.select'),
dispatch: td.function('.dispatch'),
pipe: td.function('.pipe'),
} as Store<any>;
let dispatch;
let pipe;
const mockConfigService = {
getConfiguration: td.func(() => {
return mockNotificationConfig
})
} as ConfigService;
const mockNotificationConfig = {
Env: null,
apiBaseUrl: 'blah'
} as MclNotificationConfig;
const mockRuleDataFields: RuleDataFieldDefinition[] = [
{name: 'data field 1', dataFieldId: 'mock data field guid', category: 'mock category'} as RuleDataFieldDefinition
];
fdescribe('ClientRulesConditionComponent', () => {
let component: ClientRulesConditionComponent;
let fixture: ComponentFixture<ClientRulesConditionComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ ClientRulesConditionComponent ],
imports: [ReactiveFormsModule],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
providers: [
{provide: Store, useFactory: () => mockStore},
{provide: RuleDataFieldService, useValue: mockRuleDataFields},
HttpClientTestingModule,
// {provide: ConfigService, useFactory: () => mockConfigService},
// {provide: MclNotificationConfig, useFactory: () => mockNotificationConfig},
// HttpHandler, HttpClient
]
})
.compileComponents();
}));
beforeEach(() => {
dispatch = spyOn(mockStore, 'dispatch');
pipe = spyOn(mockStore, 'pipe').and.callThrough();
fixture = TestBed.createComponent(ClientRulesConditionComponent);
component = fixture.componentInstance;
const fb: FormBuilder = new FormBuilder();
component.conditionForm = fb.group({
name: fb.control('', [Validators.required]),
triggerWhen: fb.control('', [Validators.required]),
conditions: fb.array([
fb.group({
dataField: fb.control('df1'),
conditionToMatch: fb.control('ctm1'),
value: fb.control('v1')
}),
fb.group({
dataField: fb.control('df2'),
conditionToMatch: fb.control('ctm2'),
value: fb.control('v2')
})
])
});
component.indexInConditionArray = 1;
component.submitted$ = of(false);
component.ruleDataFieldOption$ = of(mockRuleDataFields);
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
// Confirm conditionToMatch and dataField get actions have been dispatched
expect(dispatch).toHaveBeenCalledTimes(2);
// Confirm that we load the correct set of form controls and they have the correct value associated with them
const conditionsArray = component.conditionForm.controls['conditions'] as FormArray;
const conditionGroup = conditionsArray.at(component.indexInConditionArray) as FormGroup;
expect(component.dataFieldControl).toEqual(conditionGroup.controls['dataField'] as FormControl);
expect(component.dataFieldControl.value).toEqual('df2');
expect(component.matchingConditionControl).toEqual(conditionGroup.controls['conditionToMatch'] as FormControl);
expect(component.matchingConditionControl.value).toEqual('ctm2');
expect(component.valueControl).toEqual(conditionGroup.controls['value'] as FormControl);
expect(component.valueControl.value).toEqual('v2');
// Confirm the conditionToMatch and dataField selectors were wired up
expect(pipe).toHaveBeenCalledTimes(2);
// Confirm the expected value for the 'submitted' flag got emitted
expect(component.submitted).toBeFalsy();
});
});
.
.
.
,这也不起作用。
client-rules-condition.component.spec.ts
@Component({
selector: 'nd-client-rules-condition',
templateUrl: './client-rules-condition.component.html',
styleUrls: ['./client-rules-condition.component.scss']
})
export class ClientRulesConditionComponent implements OnInit {
@Input() conditionForm: FormGroup;
@Input() indexInConditionArray: number;
@Input() submitted$: Observable<boolean>;
@Output() removeCondition: EventEmitter<number> = new EventEmitter();
conditionToMatchOption$: Observable<ConditionToMatch[]>;
valueControl: FormControl;
matchingConditionControl: FormControl;
dataFieldControl: FormControl;
private static NPI_DATA_FIELD_GUID: string;
validValuePattern: string;
invalidValueError: string;
// Emits the candidate rule fields that eventually come back from the database.
// The 'data fields' combo box in the markup is wired up to this.
ruleDataFieldOption$: Observable<RuleDataFieldDefinition[]>;
// Tracks whether the parent form has been submitted.
submitted: boolean;
constructor(private _store: Store<state.AppState>) { }
ngOnInit() {
this._store.dispatch(new GetConditionToMatchOptions(''));
// Dispatch Action that causes the rule-data-field options to get retrieved from the server and slammed into the global state.
this._store.dispatch(new GetRuleDataFieldsOptions(''));
this.conditionToMatchOption$ = this._store.pipe(select(getConditionToMatchOption));
// Wire up the selector that cause the rule-data-field options to get pulled from the global state when they are set/updated
this.ruleDataFieldOption$ = this._store.pipe(select(getRuleDataFieldsSelector));
// Load GUID for NPI field to use to distinguish between different Data Field dropdown items to apply different validation in Value To Match
this.ruleDataFieldOption$.subscribe(dataFields => {
if (ClientRulesConditionComponent.NPI_DATA_FIELD_GUID == null) {
for (let df of dataFields) {
if (df.name.toLowerCase().includes('npi') || df.name.toLowerCase().includes('national provider identifier')) {
ClientRulesConditionComponent.NPI_DATA_FIELD_GUID = df.dataFieldId.toUpperCase();
break;
}
}
}
});
.
.
.
client-rules-condition.component.ts
[add_to_cart id='123']
我相信这是次要的事情,我只需要通过单元测试即可。
答案 0 :(得分:0)
尝试一下,在每个declare
的新observable
之一中。
component.ruleDataFieldOption$ = new Observable<ConditionToMatch[]>;
我不知道是否有相同的规则适用于作为对象的可观察对象本身,但是您可以尝试一下。