Aller au contenu
Filtrer les règles par style d’implémentation
Style
Les deux styles
Sévérité
mineure
S’applique à
  • Adapters driven
  • Tests

INF-04 · Un parcours critique a ses stubs écrits à la main ​

Style
Les deux styles
Sévérité
mineure
S’applique à
  • Adapters driven
  • Tests

Signal ​

  • Un parcours en plusieurs appels testé contre les seuls stubs générés : la création répond, la lecture qui suit ne la trouve pas.
  • Aucun test de l’adapter face à une erreur ou un timeout du provider.
  • Un stub forcé pour un test, qui reste en place pour les suivants.
  • Un état de stub laissé par un test, que le suivant retrouve.

Pourquoi ​

Les stubs générés sont sans état, et ne répondent que le succès. Un parcours qui crée puis relit a besoin d’un stub qui se souvient. Les pannes se forcent une à une : c’est là que l’adapter se trompe le plus souvent (PRC-01).

Exceptions ​

Aucune.

Correction ​

  • Les parcours qui comptent ont des stubs écrits à la main, avec un état en mémoire, typés par les types générés du contrat.
  • Ils passent avant les stubs générés.
  • Une erreur ou un timeout se force dans le test qui le prouve.
  • L’état et les stubs forcés se remettent à zéro après chaque test.

Adaptation ​

server.use(...) ajoute un stub en tête, pour le test en cours. server.resetHandlers() le retire dans afterEach. HttpResponse.error() simule une coupure du réseau, et delay('infinite') un provider qui ne répond plus.

Voir aussi ​

INF-03 génère les autres stubs depuis le contrat. INF-02 remet la base à zéro de la même façon.

Exemple ​

ts
// src/wallets/driven/http/rates-provider/__test__/rates-provider.stubs.ts
type Quote = components['schemas']['Quote'];

export class RatesProviderJourneys {
	readonly #quotes = new Map<string, Quote>();

	readonly stubs = [
		http.post<never, Omit<Quote, 'id'>>('*/quotes', async ({ request }) => {
			const quote: Quote = { ...(await request.json()), id: `quote-${this.#quotes.size + 1}` };
			this.#quotes.set(quote.id, quote);

			return HttpResponse.json(quote, { status: 201 });
		}),
		http.get<{ id: string }>('*/quotes/:id', ({ params }) => {
			const quote = this.#quotes.get(params.id);

			if (!quote) {
				return new HttpResponse(null, { status: 404 });
			}

			return HttpResponse.json(quote);
		}),
	];

	reset(): void {
		this.#quotes.clear();
	}
}
ts
// src/shared/__test__/http.setup.ts
const journeys = new RatesProviderJourneys();
export const server = setupServer(...journeys.stubs, ...ratesProviderStubs);

beforeAll(() => {
	server.listen({ onUnhandledRequest: 'error' });
});

afterEach(() => {
	server.resetHandlers();
	journeys.reset();
});

afterAll(() => {
	server.close();
});