Вычисленный сигнал Angular в компоненте не обновляется при изменении служебного сигнала

Почему expect(component['numberHogeNames']()).toBe(3) не проходит мой тест Angular?

Вот упрощенная версия моего кода:

// hoge-service.ts
interface HogeData {
  id: string;
  name: string;
}

export class HogeService {
  private dataSrc = signal<HogeData[]>([
    { id: '1', name: 'kage' },
    { id: '2', name: 'sage' },
    { id: '3', name: 'tage' },
    { id: '4', name: 'nage' },
    { id: '5', name: 'mage' },
    { id: '6', name: 'yage' },
    ...
  ]);

  numberHogeNames = computed<number>(() => {
    return this.dataSrc().filter((item) => item.name === 'hoge').length;
  });
}
// hoge-component.ts
@Component({
  standalone: true,
  providers: [HogeService],
  template: `<div class = "num">{{ numberHogeNames() }}</div>`,
  encapsulation: ViewEncapsulation.Emulated,
  changeDetection: ChangeDetectionStrategy.OnPush,
  ...
})
export class HogeComponent {
  private hogeService = inject(HogeService);

  protected numberHogeNames = computed<number>(() => {
    return this.hogeService.numberHogeNames();
  });
}
// hoge-component.spec.ts
describe('Hoge Test', () => {
  let component: HogeComponent;
  let fixture: ComponentFixture<HogeComponent>;
  let hogeService: HogeService;

  beforeEach(async () => {
    await TestBed.configureTestingModule({
      imports: [HogeComponent],
      providers: [HogeService],
    }).compileComponents();

    fixture = TestBed.createComponent(HogeComponent);
    component = fixture.componentInstance;
    hogeService = TestBed.inject(HogeService);
  });

  it('Case 01', async () => {
    hogeService['dataSrc'].update((current) => {
      current.forEach((item, index) => {
        if (index < 3) item.name = 'hoge';
      });
      return [...current];
    });

    // Success
    expect(hogeService.numberHogeNames()).toBe(3);

    fixture.detectChanges();

    // Failed (Expected 0 to be 3.)
    expect(component['numberHogeNames']()).toBe(3);
  })
});

Несмотря на провал теста, компонент работает корректно при использовании в реальном приложении. Значение numberHogeNames на экране обновляется, как и ожидалось, при изменении dataSrc.

Я попытался изменить частный сигнал dataSrc в HogeService, используя update(), чтобы изменить свойства name некоторых элементов на hoge. После обновления dataSrc я ожидал, что hogeService.numberHogeNames() и component['numberHogeNames']() вернутся 3, поскольку есть три элемента с именем hoge.

В тесте hogeService.numberHogeNames() корректно обновляется до 3, что является ожидаемым поведением. Однако component['numberHogeNames']() по-прежнему возвращает старое значение и не обновляется должным образом.

Я пробовал использовать fixture.detectChanges() и ждать небольшой задержки с помощью setTimeout, чтобы посмотреть, обновится ли вычисленный сигнал компонента, но эти попытки не решили проблему.

Я ожидаю, что вычисленный сигнал компонента (numberHogeNames) будет отражать изменения сигнала службы (dataSrc) так же, как это происходит в реальном приложении, где все работает так, как задумано.

Что, если вы измените его с protected на public и получите к нему доступ component.numberHogeNames()?

Benny Halperin 03.09.2024 20:41

@BennyHalperin Я пробовал изменить numberHogeNames с protected на public и получил к нему доступ напрямую с помощью component.numberHogeNames(), но проблема все еще сохраняется.

A2C 04.09.2024 03:29
Тестирование функциональных 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
50
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вам необходимо сослаться на сервис, который внедрен в компонент (т.е. component.hogeService):

    component.hogeService['dataSrc'].update((current) => {
      current.forEach((item, index) => {
        if (index < 3) item.name = 'hoge';
      });
      return [...current];
    });

Потом позже:

expect(component.hogeService.numberHogeNames()).toBe(3);

Тест после этих изменений должен пройти.

Тест прошел успешно! Поскольку это проверка HogeComponent, корректно манипулировать dataSrc из компонента. Большое спасибо за вашу помощь!

A2C 04.09.2024 18:05

Всегда пожалуйста. Мне потребовалось некоторое время, чтобы это понять 😊

Benny Halperin 04.09.2024 20:02

Буду признателен за одобрение моего ответа и повышение. Спасибо.

Benny Halperin 05.09.2024 08:37

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

Похожие вопросы

Angular 18: использовать входной сигнал в суперклассе компонентов
Предупреждение Angular Calendar: NG0956 — отслеживание по идентификатору приводило к повторному созданию всей коллекции
Использование синтаксиса @if
Как объединить строку и массив в строковой интерполяции ngfor в Angular
Каков наилучший способ совместного использования переменных SCSS между библиотеками и приложениями в монорепо Angular Nx?
Двусторонняя привязка Angular нарушена в производственной сборке - TypeError «st не является функцией»
Как динамически устанавливать или снимать флажок на основе возвращаемого логического значения из функции в Angular
Почему мои значки материалов Angular отличаются от значков Google Fonts?
Tailwind CSS IntelliSense больше не предлагает классы CSS в монорепозитории NX
RxJS: `refCount: false` в ShareReplay в сервисе с ограниченной областью действия: будет ли он завершен и будет ли собран мусор при уничтожении сервиса?