Engineering

Mock Service Worker - využití pro testování i vývoj

Ondřej Hajný
Ondřej Hajný 5 min čtení

Update 11. 11. 2024: verze msw@2.6.0 vydaná 29. 10. 2024 již obsahuje podporu WebSockets zmiňovanou ve článku.

Při vývoji webové aplikace se často setkáte s nutností testovat různé scénáře API komunikace. Nejčastěji potřebujete získat data tak, jak by přicházela ze serveru, nebo testovat, jak se aplikace chová při chybách serveru nebo při zpožděných odpovědích. Někdy je backend zcela nedostupný a může se vám hodit jej simulovat – ať už pro jednodušší vývoj nebo realističtější sprint review ukázky. Mock Service Worker (MSW) slouží ke všem těmto účelům.

Knihovna MSW umožňuje simulaci HTTP dotazů přímo v prohlížečích nebo na serverech (Node.js). Nové release candidates navíc zavádějí podobnou funkcionalitu pro WebSocket komunikaci. Pojďme se podívat na základní využití knihovny a jak může zjednodušit vývoj a testování aplikací.

Úvod do MSW

Na rozdíl od tradičních řešení, která jsou často závislá na konkrétních frameworcích nebo nástrojích, je MSW nezávislé na prostředí. Můžete jej použít s libovolným frontendovým frameworkem, včetně React, Vue, Angular nebo Solid. Pro testování je k dispozici také Node.js implementace.

Jednou z hlavních výhod MSW je možnost vytvářet znovupoužitelné mocky sdílitelné mezi různými částmi aplikace nebo i mezi týmy. Místo mockování stejného API v několika testovacích souborech nebo komponentách knihovna sedí mezi vaší aplikací a serverem a upravuje HTTP dotazy. To vede k větší efektivitě a lepší konzistenci při vývoji a testování.

MSW poskytuje podporu pro různé typy komunikace:

  • REST API – mockování klasických HTTP dotazů (jako GET, POST, PUT a dalších)
  • GraphQL – jednoduchá simulace GraphQL dotazů a mutací
  • WebSockets – v beta verzi (msw@next) nástroj přináší také podporu pro obousměrnou klient-server komunikaci

Díky tomu je MSW extrémně flexibilní nástroj, který umožňuje rychle a efektivně simulovat backendové interakce bez závislosti na jeho aktuální dostupnosti nebo stavu. Pro více informací o výhodách oproti jiným řešením je doporučen článek “Stop mocking fetch” od renomovaného instruktora Kenta C. Doddse.

Aplikace MSW v praxi

Knihovnu MSW lze využít v několika typických scénářích.

Vývoj bez dostupného backendu

  • Když vaši kolegové nestíhají implementovat nebo upravit API vaší komponenty
  • Když chcete demovat aplikace pro prezentaci nebo vytvořit jen POC, kde chcete otestovat funkcionalitu
  • Když nemáte internetové připojení, ale přesto potřebujete provádět dotazy na vzdálená API

Testování aplikace

  • Když potřebujete testovat části aplikace závislé na API dotazech nebo samotného klienta
  • Když chcete centralizovaná data pro integrační nebo end-to-end testy

Chcete mockovaná data sdílet (v rámci aplikace nebo celého týmu)

A teď dva reálné příklady.

Když má váš backenďák jiné priority

V Cookielabu jsme se při spolupráci setkali s menším IoT projektem pro lídra v elektrotechnickém průmyslu. Stručně řečeno jde o načítání hodnot z RFID teploměrných čipů, jejich ukládání a distribuci. Klient chtěl jednoduchou frontendovou aplikaci pro rychlý přehled a správu jednotlivých čipů.

Na projektu pracovali dva vývojáři a kvůli krátkému deadlinu jsme se rozhodli pracovat současně na BE i FE částech. Věděli jsme zhruba, jak bude vypadat API rozhraní, ale chtěli jsme nejprve proniknout do hardwarové části – komunikace s čipy. Abychom mezitím iterovali frontendovou aplikaci, využili jsme knihovnu pro mockování REST API.

Product owner tak měl přístup k “funkční” demo aplikaci a mohli jsme upravovat nevyhovující komponenty a ladit design. Jakmile se backendový vývojář dostal k implementaci API, stačilo pouze deaktivovat knihovnu, aplikaci otestovat a doladit případné změny schématu dotazů.

Testování WebSocketové komunikace

Otázka, kterou si pravděpodobně položil každý vývojář, který někdy vyvíjel a zejména chtěl testovat aplikace používající pro komunikaci WebSockets: Jak to testovat? Z mé zkušenosti vývojáři typicky volí jednu ze dvou cest.

Horší přístup (i když pravděpodobně běžnější) je vůbec netestovat části používající WebSocket, nebo testovat pouze navázání spojení. Výsledkem je zelený checkmark, pokrytí kódu a spokojenost.

Druhou možností je nějak tuto část testovat autenticky. Lze využít například samostatnou implementaci WS serveru, ke které se aplikace připojí v testovacím prostředí, nebo v případě end-to-end frameworků (jako Cypress nebo Playwright) přepsat chování WebSocket rozhraní přímo v prohlížeči.

S novou beta verzí MSW je tu další možnost: mockování WebSockets v MSW. Využili jsme to pro testování aplikace na projektu EAT SMART pro našeho klienta Perfect Canteen.

Pro tuto firmu dodáváme software pro vending machine ve formě ledniček – alternativu firemních kantýn nabízející moderní možnosti stravování. Každá lednice má vestavěný tablet používaný pro přehled jídel, filtrování a upozornění uživatelů na různé akce. Pro rozhraní jsme zvolili webovou aplikaci, která pro komunikaci využívá GraphQL. Vedle standardních dotazů a mutací využívá subscriptions postavené přímo na WebSockets.

V tomto případě jsme knihovnu MSW použili v end-to-end testech, kde mockujeme různé události lednice probíhající v produkci. Příkladem je tok, kde uživatel otevře lednici, vezme nádobu s jídlem a znovu ji zavře. To jsou všechny události streamující přes soket, simulované v testovacím prostředí právě touto knihovnou. Přidanou hodnotou je příležitostné využití této implementace při vývoji, kdy nepotřebujeme používat virtuální lednici (server simulující hardware), ale můžeme přímo řídit, jaká data ze serveru přicházejí.

Ukázka použití MSW knihovny

Pro demonstraci jsem připravil jednoduchou webovou aplikaci ve frameworku Solid.js. Celý projekt si můžete prohlédnout v repozitáři. Aplikace obsahuje pouze jednu stránku se dvěma fotografiemi plechovek Pringles (které autor rád sbírá) a hlasovacími tlačítky.

Na pozadí nejprve proběhne HTTP GET dotaz na data a akce po kliknutí na hlasovací tlačítka jsem implementoval pomocí WebSockets. Je to jen jednoduchá demo aplikace, takže za ní nehledejte nic většího.

Samotnou knihovnu MSW nastavíte podle pokynů v dokumentaci. Pokud ale chcete využít beta podporu WebSocket, musíte nainstalovat beta verzi msw@next (více informací viz diskuzi). Knihovna se musí zaregistrovat před spuštěním renderování aplikace (aby se service worker stihl zaregistrovat), takže váš vstupní bod vypadá přibližně takto:

async function enableMocking() {
	if (import.meta.env.VITE_ENABLE_MSW !== "true") {
		return;
	}
	const { worker } = await import("./mocks/browser");
	await worker.start();
}

enableMocking().then(() => {
	initWs();
	render(() => <App />, root);
});

V něm před renderováním aplikace zkontrolujeme env proměnnou, a pokud chceme povolit MSW, zavoláme jeho start funkci. Obsahuje definované mocky API rozhraní. Na příkladu demo aplikace vidíme:

  • Mockování HTTP GET dotazu na data http.get(“/api/v1/data”, () => HttpResponse.json(mockData)). Pomocí wrapperu knihovny jednoduše vrátíme simulovaná data.
  • Passthrough handler http.get(“*.png”, () => passthrough()), který dotaz jednoduše přepošle bez úprav. Tento případ ukazuje, že knihovna umí také dotazovat reálná API. Jsme tak schopni například získat odpověď serveru a pouze upravit data.
  • Mockování WebSockets komunikace. Poslední příklad simuluje jednoduchý WS server, který nějak reaguje na zprávy přijaté od klienta.
import { http, HttpResponse, passthrough, ws } from "msw";
import { setupWorker } from "msw/browser";

const mockData = [
	{ id: 1, votes: 1, title: "Cocktail Sauce", img: "cocktail-sauce.png" },
	{ id: 2, votes: 5, title: "Roasted Potatoes", img: "roasted-potatoes.png" },
];

const wsLink = ws.link("ws://localhost:8080");

export const worker = setupWorker(
	// REST API mocking
	http.get("/api/v1/data", () => HttpResponse.json(mockData)),
	// passthrough
	http.get("*.png", () => {
		return passthrough();
	}),
	// WS mocking
	wsLink.on("connection", ({ client }) => {
		client.addEventListener("message", (event) => {
			console.log("🚀 ~ client.addEventListener ~ event:", event);
			const data = JSON.parse(event.data);
			switch (data.action) {
				case "INCREMENT": {
					const mockedResponse = {
						id: data.id,
						votesInc: 1,
					};
					if (data.id === 1) {
						mockedResponse.votesInc = 5;
					}
					client.send(JSON.stringify(mockedResponse));
					break;
				}
				default:
					client.send(JSON.stringify(data));
					break;
			}
		});
	}),
);

Přestože je ukázková aplikace jednoduchá, výhody MSW jsou jasně viditelné. Mockovaná data a související logika jsou na jednom místě a mohla by být dále využita například v testech.

Závěr z využívání MSW

MSW je flexibilní nástroj, který může výrazně zjednodušit vývoj a testování webových aplikací. Simulací API požadavků přímo v prohlížečích vám umožňuje pokračovat v práci bez ohledu na stav backendu a testovat různé scénáře v kontrolovaném prostředí. Jeho nezávislost na frameworku a podpora REST, GraphQL a WebSockets z něj dělají univerzální řešení, které se snadno integruje do jakéhokoli vývojového procesu.

MSW je vhodný nejen pro individuální vývoj, ale také pro týmová prostředí, kde je třeba zajistit konzistenci napříč projekty. Ať už jde o unit, integrační nebo end-to-end testy, MSW poskytuje spolehlivý způsob, jak mockovat různé typy API komunikace bez složitých konfigurací.

Ondřej Hajný
Ondřej Hajný
Frontend Developer, Cookielab

Ondřej je frontend vývojář v Cookielabu. Zaměřuje se na budování čistých, testovatelných UI komponent a zlepšování vývojářského zážitku napříč projekty.

Máte projekt, který potřebuje tuto úroveň péče?

Promluvte si přímo s founderem. Nejdřív posloucháme, radíme upřímně a stavíme jen když to dává smysl.

Cookielab zakladatelé — Radek Míka, Martin Homolka, Jakub Kohout

Pojďme probrat váš byznys...

nebo

...vaši kariéru.

Otevřené pozice