Testing of standalone components
Viktor-Ivliev opened this issue · 5 comments
I need to test the correctness of translations for a component, which I can't do due to translation moc issues.
component:
<div class="row form-group">
<label class="control-label col-4">
{{ 'form.fields.example_status' | translate }}
</label>
<div class="col-8">
<ng-select
[clearable]="false"
[(ngModel)]="report.template.example_filter.status"
appTooltip="{{ 'form.fields.tooltip.example_status' | translate }}"
data-tippy-placement='right'
[disabled]="report.template.example_filter.exclude_unsubscribed"
>
<ng-option value="">
{{ 'form.example_statuses.all' | translate }}
</ng-option>
<ng-option *ngFor="let status of statuses" [value]="status">
{{ 'form.example_statuses.' + status | translate }}
</ng-option>
</ng-select>
<app-form-errors
*ngIf="errors['template.example_filter.status']"
class="field-errors"
[errors]="errors['template.example_filter.status']"
></app-form-errors>
</div>
</div>
import { Component, Input } from '@angular/core';
import { CommonModule } from '@angular/common';
import { SharedModule } from '@app/shared/shared.module';
import { Report } from '@app/example/report';
@Component({
standalone: true,
selector: 'app-example-status-filter',
templateUrl: './example-status-filter.component.html',
imports: [CommonModule, SharedModule]
})
export class ExampleStatusFilterComponent {
@Input({ required: true }) report!: Report;
@Input({ required: true }) errors = {};
statuses: string[] = ['enabled', 'disabled', 'opted_out'];
}
Test:
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import { NgSelectComponent } from '@ng-select/ng-select';
import { of } from "rxjs";
import { TranslateLoader, TranslateFakeLoader, TranslateModule, TranslateService } from '@ngx-translate/core';
import { ExampleStatusFilterComponent } from './example-status-filter.component';
import { ReportsServiceStub } from '@app/example/report/services/reports.service.spec';
class FakeLoader implements TranslateFakeLoader {
public getTranslation(_) {
return of(require('src/assets/i18n/example/reports/en.json'));
}
}
describe('ExampleStatusFilterComponent', () => {
let component: ExampleStatusFilterComponent;
let fixture: ComponentFixture<ExampleStatusFilterComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [
ExampleStatusFilterComponent,
TranslateModule.forRoot({ loader: { provide: TranslateLoader, useClass: FakeLoader } }) // and forChild
]
}).compileComponents();
// TestBed.inject(TranslateService).use('en');
fixture = TestBed.createComponent(ExampleStatusFilterComponent);
// TestBed.inject(TranslateService).use('en');
component = fixture.componentInstance;
component.report = ReportsServiceStub._items[0];
fixture.detectChanges();
});
it('shows all statuses', (done) => {
fixture.whenStable().then(() => {
const statuses = fixture.debugElement.query(By.directive(NgSelectComponent));
expect(statuses.componentInstance.itemsList.items.map((item) => item.label)).toEqual(
['All', 'Enabled', 'Disabled', 'Other Translate']
);
done()
});
});
});
The test is dropping because the translations haven't pulled up.
But if you do this: TestBed.inject(TranslateService).use('en');
I can see the getTranslation(_) visit but it has no effect on pipe and tests fail too.
I use separate translation sets for different models and everything is fine in the final project, here's an example:
import { HttpBackend } from '@angular/common/http';
import { TranslateLoader, TranslateModule, TranslateModuleConfig } from '@ngx-translate/core';
import { MultiTranslateHttpLoader } from 'ngx-translate-multi-http-loader';
export function TranslationLoaderFactory(http: HttpBackend) {
return new MultiTranslateHttpLoader(http, [
'/frontend/assets/i18n/example/reports/',
'/frontend/assets/i18n/shared/'
]);
}
const config: TranslateModuleConfig = {
loader: {
provide: TranslateLoader,
useFactory: TranslationLoaderFactory,
deps: [HttpBackend]
},
isolate: true
};
export const ReportsTranslate = TranslateModule.forChild(config);
Previously before switching to standalone I used this:
TranslateTestingModule.withTranslations({
en: require('src/assets/i18n/example/reports/en.json')
})
And the tests worked, but when switching to standalone it feels like translations are compiled before the test module is created, where providers for translations are defined.
"@angular/core": "18.2.12",
"@ngx-translate/core": "15.0.0",
Same here. but in my project I am testing only if the translation keys appears and they are correct. Unfortunately, after converting some components to standalone, nothing is rendered, even if I use
{ provide: I18NEXT_SERVICE, useClass: TranslateServiceStub },
and mock
t(key: string | Array<string>, options?: Object): string | any { return key; }
I18NEXT_SERVICE ???
@adam-ai-97
I'm thinking of trying to migrate to the next version. Seems like it would be a problem to fix here.
https://ngx-translate.org/getting-started/migration-guide/
Or try to use the standard one, but I don't like it:
https://angular.dev/guide/i18n
This is how I configure the tests for the TranslatePipe.
It works with stand alone components and properly switches the translations.
However you should use a fake translation loader to avoid it trying to load the JSONs using HTTP.