Encontro alguns problemas ao tentar escrever um teste.
Tenho um componente que inclui apenas um SignalStore
import { ChangeDetectionStrategy, Component, inject } from '@angular/core';
import { FormulaireStore } from './store/formulaire-store';
@Component({
selector: 'app-formulaire',
imports: [],
providers: [FormulaireStore],
template: `
<p>formulaire works!</p>
@if(store.context(); as ctx) {
<p>context : {{ ctx.informations }}</p>
}
`,
styleUrl: './formulaire.component.scss',
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class FormulaireComponent {
readonly store = inject(FormulaireStore);
}
import { inject } from '@angular/core';
import {
patchState,
signalStore,
withHooks,
withMethods,
withProps,
withState,
} from '@ngrx/signals';
import { rxMethod } from '@ngrx/signals/rxjs-interop';
import { pipe, switchMap, tap } from 'rxjs';
import { FormsService } from '../../services/form.service';
export interface FormulaireContexte {
informations: string;
}
type FormulaireState = {
context: Partial<FormulaireContexte> | undefined;
};
const initialState: FormulaireState = {
context: undefined,
};
export const FormulaireStore = signalStore(
withState<FormulaireState>(initialState),
withProps(() => ({
_formService: inject(FormsService),
})),
withMethods((store) => {
return {
_getContext: rxMethod<void>(
pipe(
switchMap(() => {
return store._formService.getContext();
}),
tap((context) => {
patchState(store, {
context,
});
})
)
),
};
}),
withHooks(({ _getContext }) => {
return {
onInit() {
_getContext();
},
};
})
);
e o serviço usado pelo SignalStore
import { HttpClient } from '@angular/common/http';
import { inject, Injectable } from '@angular/core';
import { Observable } from 'rxjs';
import { FormulaireContexte } from '../formulaire/store/formulaire-store';
@Injectable({ providedIn: 'root' })
export class FormsService {
readonly #client = inject(HttpClient);
getContext(): Observable<FormulaireContexte> {
return this.#client.get<FormulaireContexte>(`/api/forms/context`);
}
}
Portanto, estou tentando escrever um teste para interagir com a IU
import { TestBed } from '@angular/core/testing';
import { provideHttpClient } from '@angular/common/http';
import { FormulaireComponent } from './formulaire.component';
import { provideRouter } from '@angular/router';
import {
HttpTestingController,
provideHttpClientTesting,
} from '@angular/common/http/testing';
import { RouterTestingHarness } from '@angular/router/testing';
describe('FormulaireComponent', () => {
const setup = async () => {
TestBed.configureTestingModule({
providers: [
provideRouter([
{
path: 'formulaire',
pathMatch: 'full',
component: FormulaireComponent,
},
]),
provideHttpClient(),
provideHttpClientTesting(),
],
});
const httpCtrl = TestBed.inject(HttpTestingController);
const harness = await RouterTestingHarness.create('formulaire');
harness.fixture.autoDetectChanges(true);
httpCtrl
.match((req) => Boolean(req.url.match(`/api/forms/context`)))[0]
.flush({ informations: 'mocked informations' });
httpCtrl.verify();
return harness;
};
it('should create', async () => {
const harness = await setup();
//! This line is needed to see changes
harness.detectChanges();
debugger;
expect(1).toBe(1);
});
});
mas parece que preciso dessa linha específica
//! This line is needed to see changes
harness.detectChanges();
para entrar na condição @if do modelo.
o comportamento estranho é que se não chamar httpClient no serviço
getContext(): Observable<FormulaireContexte> {
//return this.#client.get<FormulaireContexte>(`/api/forms/context`);
return of({ informations: 'informations from of operator' });
}
Ele funciona sem a necessidade de
harness.detectChanges();
Não entendi o comportamento aqui, preciso de alguns conselhos para entendê-lo
A única diferença que vejo é que:
this.#client.get<FormulaireContexte>(
/api/forms/context);
-> demora um pouco para resolver, em vez de resolver imediatamente.of({ informations: 'informations from of operator' })
-> resolve imediatamente em comparação com a forma anterior.Também observei que a linha abaixo
autoDetectChanges
acionará um ciclo de detecção de alterações.Então pode ser apenas uma questão de tempo. O
of
é resolvido antes da detecção de alterações ser executada e a@if
condição mostra o valor correto. Enquanto othis.#client.get<FormulaireContexte>(
/api/forms/context);
é resolvido após a detecção de alterações ser executada, portanto você precisa de um adicionalfixture.detectChanges()
para o@if
para mostrar o valor correto.Para testar essa teoria, você pode fazer o
of
observável resolver com um atraso, se o comportamento for que os casos de teste passem sem chamarfixture.detectChanges()
, então minha teoria está errada. Caso contrário, está correta.