Я пытаюсь использовать токены 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
и здесь:
// 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 поставщик токена внедрения, да, есть. Вы можете видеть это здесь:
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();
});
});
Тем не менее, он по-прежнему считает, что токен инъекции не существует. Кто-нибудь знает, почему?
Спасибо!
к сожалению нет





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, спасибо за ответ! Хотя это действительно исправляет тесты, это нарушает функциональность токенов внедрения. Я хочу иметь возможность устанавливать значение токена внедрения глобально из конфигурации приложения и использовать это значение повсюду. При использовании этого метода глобальный токен переопределяется поставщиком, определенным в массиве поставщиков компонентов.
Я также создал ветку для тестирования вашего исправления, если вы хотите посмотреть. github.com/shadow1349/nx-filereplacementissue/blob/Alpine-A110R/… github.com/shadow1349/nx-filereplacementissue/blob/Alpine-A110R/…
@SamRedmond, вы можете создать своего поставщика клиентов, я обновил свой ответ;)
Попался, это работает, спасибо! У меня был еще один вопрос, который, как я понимаю, я забыл включить в исходный пост. Если бы я хотел изменить значение в компоненте приложения, как это github.com/shadow1349/nx-filereplacementissue/blob/Alpine-A110R/… как я могу заставить это изменить переменную, когда она попадает в компонент компонентов?
Я подозреваю, что начинаю вникать в то, просто используйте территорию библиотеки государственного управления, лол.
Отвечает ли это на ваш вопрос? Автономный компонент Unit Test Angular, переопределяющий поставщик не используется