I have a presentational/dumb component that uses an input to populate a HTML template using a formBuilder. This all works fine but when I start testing it things aren't as smooth as they should be.
I want to test that some text boxes are being populated correctly with the value of my input. I would expect the formGroup to update my HTML after I:
- Set the input
- Call detect changes
- Call ngOnInit
In my test I am overriding the OnPush detection strategy with the Default behaviour.
Ultimately my goal is to do snapshot testing using Jest for these kind of components because it makes comparing properties much easier, but to do that, I first need to be able to render my HTML properly.
I am running the tests with Jest, which I believe uses JsDOM.
@Component({
selector: 'network',
templateUrl: './network.component.html',
styleUrls: ['./network.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class NetworkComponent implements OnInit {
@Input() network: Network;
public formGroup: FormGroup;
constructor(private formBuilder: FormBuilder) {}
ngOnInit() {
this.formGroup = this.formBuilder.group({
details: [this.network || null],
});
}
}
<div class="container-fluid">
<form [formGroup]="formGroup" novalidate (ngSubmit)="submit()">
<div class="row">
<div class="col-4">
<h2>Details</h2>
<app-network-details formControlName="details"></app-network-details>
</div>
</div>
<div class="row">
<button class="btn btn-primary" type="submit"></button>
</div>
</form>
</div>
My app-network-details component looks like this:
@Component({
selector: 'app-network-details',
templateUrl: './network-details.component.html',
styleUrls: ['./network-details.component.scss'],
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => NetworkDetailsComponent),
multi: true
}
],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class NetworkDetailsComponent implements OnInit, ControlValueAccessor, OnChanges {
public details = {};
@Output() change = new EventEmitter<number>();
propagateChange = (_: any) => {};
ngOnChanges(changes: SimpleChanges): void {
this.propagateChange(this.details);
}
writeValue(obj: any): void {
if (obj) {
this.details = obj;
}
}
registerOnChange(fn: any): void {
this.propagateChange = fn;
}
registerOnTouched(fn: any): void {}
setDisabledState?(isDisabled: boolean): void {
// throw new Error('Method not implemented.');
}
public onChange(e: any) {
this.details[e.target.name] = e.target.value;
this.propagateChange(this.details);
}
constructor() {
this.details = {};
}
ngOnInit() {}
}
<div class="form-group">
<input class="form-control" type="text" placeholder="Name" name="name" (change)="onChange($event)" [value]="details.name || null"
/>
</div>
<div class="form-group">
<input class="form-control" type="text" placeholder="Description" name="description" (change)="onChange($event)" [value]="details.description || null"
/>
</div>
<div class="form-group">
<input class="form-control" type="text" placeholder="Local Code" name="localCode" (change)="onChange($event)" [value]="details.localCode || null"
/>
</div>
And here is my test setup:
describe('NetworkComponent', () => {
let component: NetworkComponent;
let fixture: ComponentFixture<NetworkComponent>;
const compilerConfig = { preserveWhitespaces: false } as any;
beforeEach(
async(() => {
TestBed.configureCompiler(compilerConfig)
.configureTestingModule({
declarations: [
NetworkComponent,
NetworkDetailsComponent,
NetworkAuthorisationComponent,
MailboxListStubComponent,
AddMailboxStubComponent,
UpdateMailboxStubComponent,
DropdownStubComponent
],
imports: [ReactiveFormsModule],
providers: [{ provide: ComponentFixtureAutoDetect, useValue: true }]
})
.overrideComponent(NetworkComponent, {
set: {
changeDetection: ChangeDetectionStrategy.Default
}
})
.compileComponents();
})
);
beforeEach(() => {
fixture = TestBed.createComponent(NetworkComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should intialize inputs with values from network', () => {
const network: Network = {
id: 1,
name: 'a',
description: 'b',
localCode: 'c',
authorisation: 'd',
company: 'e',
networkType: 'oftp'
};
component.network = network;
fixture.detectChanges();
component.ngOnInit();
const inputElement = fixture.nativeElement.querySelector('input[name="description"]');
inputElement.dispatchEvent(new Event('change'));
fixture.detectChanges();
expect(inputElement.value).toEqual('b');
});
});
Aucun commentaire:
Enregistrer un commentaire