Angular computed signal in component does not update when service signal changes

Discussão em 'Angular' iniciado por A2C, Novembro 21, 2024.

  1. A2C

    A2C Guest

    Why does expect(component['numberHogeNames']()).toBe(3) fail in my Angular test?

    Here is a simplified version of my code:

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


    Despite the test failure, the component works correctly when used in the actual application. The value of numberHogeNames on the screen updates as expected when dataSrc changes.

    I tried modifying the private dataSrc signal in the HogeService by using update() to change some items' name properties to hoge. After updating dataSrc, I expected both hogeService.numberHogeNames() and component['numberHogeNames']() to return 3 since there are three items with the name hoge.

    In the test, hogeService.numberHogeNames() updates correctly to 3, which is the expected behavior. However, component['numberHogeNames']() still returns the old value and does not update as expected.

    I have tried using fixture.detectChanges() and waiting for a short delay using setTimeout to see if the component’s computed signal would update, but these attempts did not resolve the issue.

    I expect the component’s computed signal (numberHogeNames) to reflect the changes in the service's signal (dataSrc) just as it does in the actual application where everything works as intended.

    Continue reading...

Compartilhe esta Página