Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Testing of standalone components #1508

Open
Viktor-Ivliev opened this issue Dec 11, 2024 · 4 comments
Open

Testing of standalone components #1508

Viktor-Ivliev opened this issue Dec 11, 2024 · 4 comments

Comments

@Viktor-Ivliev
Copy link

Viktor-Ivliev commented Dec 11, 2024

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",
@adam-ai-97
Copy link

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; }

@CodeAndWeb
Copy link
Member

I18NEXT_SERVICE ???

@Viktor-Ivliev
Copy link
Author

@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

@CodeAndWeb
Copy link
Member

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants