Scenario
In my testing process, I am evaluating a component that utilizes an observable-based service to retrieve and display data for internationalization purposes.
The i18n service is custom-made to cater to specific requirements.
While the component functions correctly in development mode (used in various templates), it fails during testing.
Details
Component Details
@Component({
selector : "i18n",
template : '<span [innerHTML]="text"></span><span #wrapper hidden="true"><ng-content></ng-content><span>',
encapsulation: ViewEncapsulation.None
})
export class I18nComponent implements OnChanges {
constructor(private i18n:I18n) {
}
@ViewChild('wrapper')
content:ElementRef;
@Input('key')
key:string;
@Input('domain')
domain:string;
@Input('variables')
variables:Variables = [];
@Input("plural")
plural:number;
text:string;
ngOnChanges():any {
this.i18n.get(this.key, this.content.nativeElement.innerHTML, this.variables, this.domain).subscribe((res) => {
this.text = res;
});
}
}
I18n.get
public get(key:string,
defaultValue?:string,
variables:Variables = {},
domain?:string):Observable<string>{
const catalog = {
"StackOverflowDomain":
{
"my-key":"my-value"
}
};
return Observable.of(catalog[domain][key]).delay(300);
}
using Variables
:
export interface Variables {
[key:string]:any;
}
Testing Process
describe("I18n component", () => {
beforeEach(() => {
TestBed.configureTestingModule({
providers : [
I18n,
{
provide : I18N_CONFIG,
useValue: {
defaultLocale : "fr_FR",
variable_start: '~',
variable_end : '~'
}
},
{
provide : I18N_LOADERS,
useClass: MockLocaleLoader,
multi : true
}
],
declarations: [
I18nComponent
]
});
fixture = TestBed.createComponent<I18nComponent>(I18nComponent);
comp = fixture.componentInstance;
});
fit("can call I18n.get.", fakeAsync(() => {
comp.content.nativeElement.innerHTML = "nope";
comp.key = "test";
comp.domain = "test domain";
comp.ngOnChanges();
tick();
fixture.detectChanges();
expect(comp.text).toBe("test value");
}));
});
Issue Encountered
The test is failing with the following message:
Expected undefined to be 'test value'.
Error: 1 periodic timer(s) still in the queue.
This failure occurs because the i18n.get
function has not completed its task before the assertion is verified, resulting in comp.text
remaining as undefined
.
Solutions Attempted
- Attempting to adjust the value in the
tick
method by setting it significantly high (tried with 5000) did not yield any changes. - Creating
ngOnChanges
to return aPromise<void>
that resolves immediately afterthis.text = res;
and switching fromfakeAsync
zone to a simple test utilizing adone
method called in thethen
ofcomp.ngOnChanges
. This solution worked; however,ngOnChanges
should not return aPromise
, therefore seeking a cleaner alternative.