Skip to content

Instantly share code, notes, and snippets.

@IlCallo
Last active May 17, 2019 12:41
Show Gist options
  • Save IlCallo/a003f4f0a12b4e0276d461d5ff8c2562 to your computer and use it in GitHub Desktop.
Save IlCallo/a003f4f0a12b4e0276d461d5ff8c2562 to your computer and use it in GitHub Desktop.
Testing code inside ngOnChanges (and in components using OnPush) using Spectator
import { Component, Directive, Host, Input, OnChanges, SimpleChanges } from '@angular/core';
import { createHostComponentFactory, SpectatorWithHost } from '@netbasal/spectator/jest';
@Component({
selector: 'simple-component',
template: '{{ name }}'
})
class SimpleComponent implements OnChanges {
@Input() name!: string;
ngOnChanges(changes: SimpleChanges) {
console.log('ngOnChanges from Component, name: ', changes['name']);
}
}
@Directive({
selector: '[simpleDirective]'
})
class SimpleDirective implements OnChanges {
@Input() nameButStronger!: string;
constructor(@Host() private host: SimpleComponent) {}
ngOnChanges(changes: SimpleChanges) {
console.log('ngOnChanges from Directive, name: ', changes['nameButStronger']);
this.host.name = changes['nameButStronger'].currentValue + ', stronger!';
}
}
@Component({
selector: 'host',
template: ''
})
class HostComponent {
nameMirror!: string;
nameButStrongerMirror!: string;
}
// During a Change Detection cycle (automatic or triggered with detectChanges()).
// ngOnChanges hook it's called only when at least a change is registered on @Input properties.
// Programmatic manipulation of properties on the component effectively prevents the @Input mechanism to notice the change.
// These methods are or perform programmatic manipulations and as such won't cause ngOnChanges hook to be called.
// * directive.nameButStronger = 'Luca';
// * host.setInput('nameButStronger', 'Paolo');
// * createHost(`<simple-component simpleDirective></simple-component>`, undefined, { nameButStronger: 'Simone' } );
//
// The only working way, aside manually calling ngOnChanges hook, is to create a custom host component with properties bound
// via template to the tested component/directive @Input properties, update host component mirror properties
// and then force a Change Detection cycle (using detectChanges()).
describe('SimpleComponent and SimpleDirective', () => {
let host: SpectatorWithHost<SimpleDirective, HostComponent>;
const createHost = createHostComponentFactory({
component: SimpleDirective,
declarations: [SimpleComponent],
host: HostComponent
});
it('should correctly call ngOnChanges hook and detectChanges on SimpleComponent', () => {
host = createHost(`<simple-component [name]="nameMirror"></simple-component>`);
const component = host.queryHost<SimpleComponent>(SimpleComponent);
const componentElement = host.queryHost('simple-component');
host.hostComponent.nameMirror = 'Paolo';
host.detectChanges();
console.log('Current host content: ', host.hostElement.innerHTML);
console.log('Component property: ', component.name);
expect(componentElement).toHaveText('Paolo');
host.hostComponent.nameMirror = 'Luca';
host.detectChanges();
console.log('Current host content: ', host.hostElement.innerHTML);
console.log('Component property: ', component.name);
expect(componentElement).toHaveText('Luca');
host.hostComponent.nameMirror = 'Simone';
host.detectChanges();
console.log('Current host content: ', host.hostElement.innerHTML);
console.log('Component property: ', component.name);
expect(componentElement).toHaveText('Simone');
});
it('should correctly call ngOnChanges hook and detectChanges on SimpleDirective', () => {
host = createHost(
`<simple-component [nameButStronger]="nameButStrongerMirror" simpleDirective></simple-component>`
);
const component = host.queryHost<SimpleComponent>(SimpleComponent);
const componentElement = host.queryHost('simple-component');
const directive = host.getDirectiveInstance<SimpleDirective>(SimpleDirective);
host.hostComponent.nameButStrongerMirror = 'Paolo';
host.detectChanges();
console.log('Current host content: ', host.hostElement.innerHTML);
console.log('Directive property: ', directive.nameButStronger);
console.log('Component property: ', component.name);
expect(componentElement).toHaveText('Paolo, stronger!');
host.hostComponent.nameButStrongerMirror = 'Luca';
host.detectChanges();
console.log('Current host content: ', host.hostElement.innerHTML);
console.log('Directive property: ', directive.nameButStronger);
console.log('Component property: ', component.name);
expect(componentElement).toHaveText('Luca, stronger!');
host.hostComponent.nameButStrongerMirror = 'Simone';
host.detectChanges();
console.log('Current host content: ', host.hostElement.innerHTML);
console.log('Directive property: ', directive.nameButStronger);
console.log('Component property: ', component.name);
expect(componentElement).toHaveText('Simone, stronger!');
});
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment