*Update 11. 11. 2024: verze msw@2.6.0 vydaná 29. 10. 2024 již obsahuje podporu WebSockets zmiňovanou ve článku.
https://mswjs.io/docs/basics/handling-websocket-events
https://github.com/mswjs/msw/releases/tag/v2.6.0
Při vývoji webových aplikací se často setkáte s potřebou testovat různé scénáře komunikace s API. Nejčastěji je třeba dostat data tak, jak by vám přišla ze serveru, nebo vyzkoušet, jak se aplikace chová, když server vrací chyby nebo se odpověď zpozdí. Někdy také backend chybí úplně a vám se může hodit si ho nasimulovat, ať už pro jednodušší vývoj, nebo reálnější ukázku na páteční sprint review. Ve všech těchto případech poslouží Mock Service Worker (MSW).
Knihovna MSW umožňuje simulovat HTTP dotazy přímo v prohlížeči nebo na serveru (Node.js). Nové RC navíc přináší obdobnou funkcionalitu i pro komunikaci pomocí WebSockets. Pojďte se podívat na základní použití knihovny i to, jak vám může usnadnit práci při vývoji a testování aplikací.
Na rozdíl od tradičních řešení, která často závisejí na konkrétních frameworcích nebo nástrojích, je MSW nezávislý na prostředí. Můžete ho použít s jakýmkoli frontendovým frameworkem, včetně React, Vue, Angular nebo třeba Solid. Pro testování je možné využít i implementaci pro Node.js.
Jedním z hlavních přínosů MSW je možnost vytvářet znovupoužitelné mocky, které lze sdílet napříč různými částmi aplikace, nebo dokonce mezi týmy. Místo toho, abyste mockovali stejné API v několika testovacích souborech nebo komponentách, knihovna stojí 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:
To všechno dělá z MSW velmi flexibilní nástroj, který vám umožní rychle a efektivně simulovat interakce s vaším backendem, aniž byste byli závislí na jeho aktuální dostupnosti nebo stavu. Pokud vás výhody oproti ostatním řešením zajímají více, doporučuji si přečíst článek Stop mocking fetch od známého instruktora Kenta C. Doddse.
Knihovna MSW se dá využít v několika typických případech.
Vývoj bez dostupného backendu
Testování aplikace
Chcete mockovaná data sdílet (v rámci aplikace nebo celého týmu)
A teď už dva příklady z reálného života.
V Cookielabu jsme se přes naši spolupráci dostali k malému IoT projektu pro lídra v oblasti elektrotechnického průmyslu. Ve zkratce jde o načítání hodnot z RFID čipů měřících teplotu, jejich ukládání a distribuci. K tomu chtěl klient jednoduchou frontendovou aplikaci pro rychlý přehled a ovládání jednotlivých čipů.
Na projektu jsme dělali dva vývojáři a kvůli krátkému deadlinu jsme se rozhodli pracovat současně jak na BE, tak na FE části. Věděli jsme, jak zhruba bude vypadat API rozhraní, ale jako první jsme chtěli prokopnout hardwarovou část – tedy komunikaci s čipy. Abychom ale mohli mezitím iterovat frontendovou aplikaci, využili jsme knihovnu pro mockování REST API.
Produkťák tak měl k dispozici „funkční“ demo aplikaci a mohli jsme upravovat nevyhovující komponenty a ladit design. V momentě, kdy se backenďák dostal i na implementaci API, stačilo jen knihovnu vypnout, aplikaci otestovat a doladit případné změny ve schématu dotazů.
Otázka, kterou si asi položil každý, kdo někdy vyvíjel a hlavně chtěl otestovat aplikaci používající ke komunikaci WebSockets: Jak to otestovat? Z mé zkušenosti se vývojáři typicky vydají po jedné ze dvou cest.
Ta podle mě horší (ale asi častější) je netestovat části používající WebSockets vůbec, případně otestovat jen navázání spojení. Tím pádem mám zelenou fajfku, code coverage a jsem spokojený.
Druhá možnost je nějakým způsobem tuto část otestovat doopravdy. K tomu se dá využít např. implementace separátního WS serveru, na který se aplikace v testovacím prostředí připojí, nebo v případě end-2-end frameworku (jako Cypress nebo Playwright) přepsat chování samotného WebSockets rozhraní v browseru.
S novou beta verzí MSW knihovny je tady ale další možnost: mockování WebSockets v MSW (pozn. autora: odkaz vede na beta verzi dokumentace). A tu jsme využili my pro testování aplikace na projektu EAT SMART pro našeho klienta Perfect Canteen.
Pro tuto firmu dodáváme software pro automaty ve formě lednic, které jsou alternativou firemních kantýn a nabízejí moderní variantu stravování (více se můžete dočíst v naší případovce o projektu). Každá lednice má zabudovaný tablet, který slouží k přehledu jídel a jejich filtrování a případně uživatele upozorňuje na různé akce. Pro rozhraní jsme zvolili webovou aplikaci, která ke komunikaci využívá GraphQL. Vedle standardních queries a mutations ale utilizuje i subscriptions, která jsou postavena právě na WebSockets.
Knihovnu MSW jsme v tomto případě použili v end-2-end testech, kde s její pomocí mockujeme různé události lednice, které nastávají na produkci. Jako příklad můžeme uvést flow, kdy uživatel otevře lednici, vezme krabičku s jídlem a lednici opět zavře. To všechno jsou události proudící socketem a v testovacím prostředí je simulujeme právě knihovnou. Výhodou navíc je, že občas tuto implementaci použijeme i při vývoji, kdy nemusíme využívat tzv. virtuální lednici (tedy server simulující hardware), ale můžeme přímo ovládat, co za data nám ze serveru chodí.
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, na které nalezneme dvě fotky Pringles plechovek (které autor rád sbírá 🙃) a tlačítka pro hlasování.
Na pozadí proběhne nejdříve HTTP GET dotaz na data a akce po kliknutí na hlasovací tlačítka jsem implementoval pomocí WebSockets. Je to jen hloupá ukázková aplikace, takže za tím nehledejte nic většího.
Samotnou knihovnu MSW nastavíte podle návodu v dokumentaci. Pokud ale chcete využít i beta podporu pro WebSockets, musíte nainstalovat beta verzi msw@next (pro více informací projděte diskuzi). Knihovna se musí zaregistrovat ještě před startem renderingu samotné aplikace (aby se stačil zaregistrovat service worker), takže váš entry point bude vypadat nějak takhle:
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 renderingem aplikace zkontrolujeme env proměnnou, a pokud chceme zapnout MSW, tak zavoláme jeho <inline-code>start<inline-code> funkci. Ta obsahuje nadefinované mocky pro API rozhraní. V příkladu z demo aplikace můžeme vidět:
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 ukázková aplikace je jednoduchá, můžeme na ní pěkně vidět přednosti MSW. Mockování dat a logiku okolo máme na jednom místě a mohli bychom ji dále využít např. v testech.
MSW je flexibilní nástroj, který může významně usnadnit vývoj i testování webových aplikací. Díky možnosti simulovat API požadavky přímo v prohlížeči 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 pro REST, GraphQL i WebSockets z něj dělají univerzální řešení, které se snadno integruje do jakéhokoli vývojového procesu.
MSW se hodí nejen pro individuální vývoj, ale i pro práci v týmech a v prostředích, kde je třeba zajistit konzistenci napříč projekty. Ať už se jedná o jednotkové, integrační, nebo end-2-end testy, MSW poskytuje spolehlivý způsob, jak mockovat různé typy API komunikace bez nutnosti složitých konfigurací.