Модульные тесты NX Angular завершаются неудачей из-за NullInjectorError

Я пытаюсь использовать токены Angular Injection Tokens в своем приложении, но это продолжает вызывать сбой моих модульных тестов.

Вот репозиторий, который демонстрирует проблему:

https://github.com/shadow1349/nx-filereplacementissue/tree/main

Если вы проверите основную ветку, запустите npm install, а затем запустите npx nx run test:test, вы увидите следующую ошибку:

NullInjectorError: R3InjectorError(Standalone[ComponentsComponent])
[InjectionToken TEST_INJECTION_TOKEN -> InjectionToken TEST_INJECTION_TOKEN -> InjectionToken TEST_INJECTION_TOKEN]:
NullInjectorError: No provider for InjectionToken TEST_INJECTION_TOKEN!

Вот мой токен инъекции, расположенный здесь: https://github.com/shadow1349/nx-filereplacementissue/blob/main/shared/injection-tokens/src/index.ts

export const TEST_INJECTION_TOKEN = new InjectionToken<BehaviorSubject<string>>(
  'TEST_INJECTION_TOKEN'
);

Конфигурация моего приложения находится здесь: https://github.com/shadow1349/nx-filereplacementissue/blob/main/test/src/app/app.config.ts

import { ApplicationConfig } from '@angular/core';
import { provideRouter } from '@angular/router';
import { appRoutes } from './app.routes';
import { TEST_INJECTION_TOKEN } from '@test-filereplacements/injection-tokens';
import { BehaviorSubject } from 'rxjs';

export const appConfig: ApplicationConfig = {
  providers: [
    provideRouter(appRoutes),
    {
      provide: TEST_INJECTION_TOKEN,
      useValue: new BehaviorSubject<string>('Hello World'),
    },
  ],
};

Затем у меня есть общий компонент, импортированный в мой компонент приложения, под названием ComponentsComponent, расположенный здесь:

https://github.com/shadow1349/nx-filereplacementissue/blob/main/test/src/app/app.comComponent.ts

и здесь:

https://github.com/shadow1349/nx-filereplacementissue/blob/main/shared/comComponents/src/lib/comComponents/comComponents.comComponent.ts

// app component
import { Component } from '@angular/core';
import { RouterModule } from '@angular/router';
import { NxWelcomeComponent } from './nx-welcome.component';
import { ComponentsComponent } from '@test-filereplacements/components';

@Component({
  standalone: true,
  imports: [NxWelcomeComponent, RouterModule, ComponentsComponent],
  selector: 'test-filereplacements-root',
  templateUrl: './app.component.html',
  styleUrl: './app.component.scss',
})
export class AppComponent {}

//components.component.ts
import { Component, Inject } from '@angular/core';
import { CommonModule } from '@angular/common';
import { TEST_INJECTION_TOKEN } from '@test-filereplacements/injection-tokens';
import { BehaviorSubject } from 'rxjs';

@Component({
  selector: 'test-filereplacements-components',
  standalone: true,
  imports: [CommonModule],
  templateUrl: './components.component.html',
  styleUrl: './components.component.css',
})
export class ComponentsComponent {
  constructor(
    @Inject(TEST_INJECTION_TOKEN) public testToken: BehaviorSubject<string>
  ) {
    console.info('testToken', this.testToken);
  }
}

Все это отлично работает, когда вы запускаете npx nx run test:serve --configuration=development, он отлично ведет журнал консоли.

Вот тут-то вы и столкнетесь с проблемой. Если вы запустите тест с помощью Jest, он пройдет. Однако при запуске npx nx run test:test происходит сбой:

NullInjectorError: R3InjectorError(Standalone[ComponentsComponent])
[InjectionToken TEST_INJECTION_TOKEN -> InjectionToken TEST_INJECTION_TOKEN -> InjectionToken TEST_INJECTION_TOKEN]:
NullInjectorError: No provider for InjectionToken TEST_INJECTION_TOKEN!

Я знаю, что первый вопрос, который вы зададите, заключается в том, есть ли в app.comComponent.ts поставщик токена внедрения, да, есть. Вы можете видеть это здесь:

https://github.com/shadow1349/nx-filereplacementissue/blob/main/test/src/app/app.comComponent.spec.ts

import { ComponentFixture, TestBed } from '@angular/core/testing';
import { AppComponent } from './app.component';
import { NxWelcomeComponent } from './nx-welcome.component';
import { RouterTestingModule } from '@angular/router/testing';
import { TEST_INJECTION_TOKEN } from '@test-filereplacements/injection-tokens';
import { BehaviorSubject } from 'rxjs';

describe('AppComponent', () => {
  let component: AppComponent;
  let fixture: ComponentFixture<AppComponent>;

  beforeEach(async () => {
    await TestBed.configureTestingModule({
      imports: [AppComponent, NxWelcomeComponent, RouterTestingModule],
      providers: [
        {
          provide: TEST_INJECTION_TOKEN,
          useValue: new BehaviorSubject<string>('Hello World'),
        },
      ],
    }).compileComponents();

    fixture = TestBed.createComponent(AppComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
  });

  it('should exist', () => {
    expect(component).toBeTruthy();
  });
});

Тем не менее, он по-прежнему считает, что токен инъекции не существует. Кто-нибудь знает, почему?

Спасибо!

к сожалению нет

Sam Redmond 25.03.2024 20:03
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Angular и React для вашего проекта веб-разработки?
Angular и React для вашего проекта веб-разработки?
Когда дело доходит до веб-разработки, выбор правильного front-end фреймворка имеет решающее значение. Angular и React - два самых популярных...
Эпизод 23/17: Twitter Space о будущем Angular, Tiny Conf
Эпизод 23/17: Twitter Space о будущем Angular, Tiny Conf
Мы провели Twitter Space, обсудив несколько проблем, связанных с последними дополнениями в Angular. Также прошла Angular Tiny Conf с 25 докладами.
Угловой продивер
Угловой продивер
Оригинал этой статьи на турецком языке. ChatGPT используется только для перевода на английский язык.
Мое недавнее углубление в Angular
Мое недавнее углубление в Angular
Недавно я провел некоторое время, изучая фреймворк Angular, и я хотел поделиться своим опытом со всеми вами. Как человек, который любит глубоко...
Освоение Observables и Subjects в Rxjs:
Освоение Observables и Subjects в Rxjs:
Давайте начнем с основ и постепенно перейдем к более продвинутым концепциям в RxJS в Angular
0
2
65
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий
NullInjectorError: R3InjectorError(Standalone[ComponentsComponent])
[InjectionToken TEST_INJECTION_TOKEN -> InjectionToken TEST_INJECTION_TOKEN -> InjectionToken TEST_INJECTION_TOKEN]:
NullInjectorError: No provider for InjectionToken TEST_INJECTION_TOKEN!

Токен внедрения предоставляется в конструкторе ComponentsComponent.ts.

Чтобы решить эту проблему, вам необходимо предоставить InjectionToken в вашем компоненте:

Подход с поставщиком клиентов: создайте своего поставщика клиентов, и его можно будет вызывать на корневом уровне и на уровне функций.

export const provideToken = (value = 'TEST 123') => {
  const providers: Provider[] = [
    {
      provide: TEST_INJECTION_TOKEN,
      useValue: new BehaviorSubject<string>(value),
    }
  ];
  return providers;
};

КомпонентыКомпонент с поставщиком клиентов:

@Component({
  selector: 'test-filereplacements-components',
  standalone: true,
  imports: [CommonModule],
  templateUrl: './components.component.html',
  styleUrl: './components.component.css',
  providers: [
    provideToken()
  ],
})

И app.config.ts

export const appConfig: ApplicationConfig = {
  providers: [
    provideRouter(appRoutes),
    provideToken()
  ],
};

Привет @Alpine A110R, спасибо за ответ! Хотя это действительно исправляет тесты, это нарушает функциональность токенов внедрения. Я хочу иметь возможность устанавливать значение токена внедрения глобально из конфигурации приложения и использовать это значение повсюду. При использовании этого метода глобальный токен переопределяется поставщиком, определенным в массиве поставщиков компонентов.

Sam Redmond 26.03.2024 16:00

Я также создал ветку для тестирования вашего исправления, если вы хотите посмотреть. github.com/shadow1349/nx-filereplacementissue/blob/Alpine-A1‌​10R/… github.com/shadow1349/nx-filereplacementissue/blob/Alpine-A1‌​10R/…

Sam Redmond 26.03.2024 16:05

@SamRedmond, вы можете создать своего поставщика клиентов, я обновил свой ответ;)

Alpine A110R 26.03.2024 16:56

Попался, это работает, спасибо! У меня был еще один вопрос, который, как я понимаю, я забыл включить в исходный пост. Если бы я хотел изменить значение в компоненте приложения, как это github.com/shadow1349/nx-filereplacementissue/blob/Alpine-A1‌​10R/… как я могу заставить это изменить переменную, когда она попадает в компонент компонентов?

Sam Redmond 26.03.2024 17:03

Я подозреваю, что начинаю вникать в то, просто используйте территорию библиотеки государственного управления, лол.

Sam Redmond 26.03.2024 17:13

Другие вопросы по теме

Получите все реализации данного типа из IServiceProvider независимо от того, имеют ли они ключ или нет
Как получить правильный экземпляр IServiceProvider в моем методе расширения
Как я могу изменить промежуточное программное обеспечение или его регистрацию, чтобы правильно использовать службу с заданной областью?
Ошибка DI консольного приложения .NET 8 «Невозможно разрешить службу для типа Microsoft.Extensions.Logging.ILoggerFactory»
FastAPI переопределяет зависимости и безопасность
Можно ли управлять внедрением bean-компонентов с помощью общих типов в Spring?
Доступ к элементам внедрения зависимостей, таким как IConfiguration, из вложенного класса в консольном приложении Core
Как зарегистрировать несколько сервисов, реализующих один и тот же интерфейс, и внедрить их в конструктор контроллера
Какая необходимость в первичном, если Квалификатор может выполнить всю работу?
Функции Azure в .Net 8 с Entity Framework Core