Purpose
Although I used mock service worker(msw) with Nuxt3, it was a little difficult because of a few articles for msw2.0 using Nuxt3. So I decided to write an article about msw2.0 to share my knowledge about it.
What is msw?
Mock service worker is a API mocking library for Node.js and browser. In this case, I will share my knowledge about using msw with browser and Nuxt3.
Why should we use msw?
- You don't need to wait implementing API.
When we develop frontend, we need to prepare API endpoints. If you prepare it yourself or BE team already implemented it. this is not a problem. However, if you would like to use some APIs and it's not prepared yet, it could be a problem. Of course you can use hardcoded Json file, this is not a good idea to try API request and responce. Msw is a API mocking service for browser and Node.js, so we don't need to be hurry to prepare some real API endpoints.
- You can use this mock in test, storybook as well.
If you define some handlers with msw, you can use it everywhere. If you use pure jest, you need to define some method(such as mock(), spyOn()…) each place. So, you can reduce your code and repeated func or method as well thanks to msw. You can also use these defined mocks in storybook as well.
How should we use msw?
Step
- Install msw library(You can install by yarn or CDN)
npm install msw --save-dev- Copy the worker script
npx msw init <PUBLIC_DIR> // such as publicThe official docs says like below
Once copied, navigate to the /mockServiceWorker.js URL of your application
in your browser (e.g. if your application is running on http://localhost:3000,
go to the http://localhost:3000/mockServiceWorker.js route).- Set up your mock
// src/mocks/browser.js
import { setupWorker } from 'msw/browser'
import { handlers } from './handlers'
export const worker = setupWorker(...handlers)If you would like to use several handlers, you can set your handlers like below.
// src/mocks/handlers/index.ts
import { handlers as test1Handlers } from './test1';
import { handlers as test2Handlers } from './test2';
import { handlers as test3Handlers } from './test3';
import { handlers as test4Handlers } from './test4';
export const handlers = [...test1Handlers, ...test2Handlers, ...test3Handlers, ...test4Handlers];- Conditionally enable mocking
If you use react, you can use like below.
import React from "react";
import ReactDOM from "react-dom/client";
import { App } from "components/App";
async function deferRender() {
if (process.env.NODE_ENV !== 'development') {
return
}
const { worker } = await import("./mocks/browser");
return worker.start()
deferRender().then(() => {
ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render(
<React.StrictMode>
<App />
</React.StrictMode>,
);
});The basic route is http://localhost:3000/mockServiceWorker.js
If you want to change route, you can set like below.
async function deferRender() {
if (process.env.NODE_ENV !== 'development') {
return
}
const { worker } = await import("./mocks/browser");
return worker.start({
serviceWorker: {
url: `test/mockServiceWorker.js`,
},
});
}If you want to set manually, you can set like below.
import { ENABLE_MSW } from "application.config.json";
async function deferRender() {
if (!ENABLE_MSW) {
return;
}
const { worker } = await import("./mocks/browser");
return worker.start({
serviceWorker: {
url: `${URL_BASE_PATH}/mockServiceWorker.js`,
},
});
}
// application.config.json
{
"ENABLE_MSW": false, // you can handle your mock here
}When you want to use with Nuxt3, you need to import as plugin like below.
// nuxt.config.ts
import { defineNuxtConfig } from 'nuxt/config';
export default defineNuxtConfig({
...
plugins: [
'@@/plugins/msw',
],
...
});
// plugins/msw.ts
import { defineNuxtPlugin } from "@@/.nuxt/imports";
import { worker } from "../src/mocks/browser";
export default defineNuxtPlugin(() => {
worker.start();
});Then, you can write your handle like below.
// src/mocks/handlers/pages.ts
import { http, HttpResponse } from 'msw';
const TENANT_ID = 'test-tenant-id';
const TEST_ID_1 = 'test-id-1';
const TEST_ID_2 = 'test-id-2';
const TEST_ID_3 = 'test-id-3';
export const handlers = [
http.get(`/api/v1/tenants/${TENANT_ID}/tests`, (req) => {
if (!req) {
return new HttpResponse(null, { status: 404 });
}
const mockResponse = {
data: [
{
test1: "test1"
},
{
test2: "test2"
},
{
test3: "test3"
},
],
message: 'Test returned successfully',
status: 200,
};
return HttpResponse.json(mockResponse);
}),
http.get(`/api/v1/tenants/${TENANT_ID}/tests/:test_id`, (req) => {
if (!req) {
return new HttpResponse(null, { status: 404 });
}
if (req.params.test_id === TEST_ID_1) {
return HttpResponse.json({
data: {
test1: "test1",
},
message: 'Test returned successfully',
status: 201,
});
}
if (req.params.test_id === TEST_ID_2) {
return HttpResponse.json({
data: {
test2: "test2",
},
message: 'Test returned successfully',
status: 201,
});
}
if (req.params.test_id === TEST_ID_3) {
return HttpResponse.json({
data: {
test3: "test3",
},
message: 'Test returned successfully',
status: 201,
});
}
return HttpResponse.json('other test id');
}),
http.post(`/api/v1/tenants/${TENANT_ID}/tests`, (req) => {
if (!req) {
return new HttpResponse(null, { status: 404 });
}
return HttpResponse.json({
data: {
test1: "test1",
},
message: 'Test returned successfully',
status: 201,
});
}),
http.delete(`/api/v1/tenants/${TENANT_ID}/tests/:test_id`, (req) => {
if (!req) {
return new HttpResponse(null, { status: 404 });
}
if (req.params.test_id === TEST_ID_1) {
return HttpResponse.json({
data: {
id: 'test-data-id-1',
},
message: 'Test returned successfully',
status: 201,
});
}
if (req.params.test_id === TEST_ID_2) {
return HttpResponse.json({
data: {
id: 'test-data-id-2',
},
message: 'Test returned successfully',
status: 201,
});
}
if (req.params.test_id === TEST_ID_3) {
return HttpResponse.json({
data: {
id: 'test-data-id-3',
},
message: 'Test returned successfully',
status: 201,
});
}
return HttpResponse.json('other test id');
}),
http.put(`/api/v1/tenants/${TENANT_ID}/tests/:test_id`, (req) => {
if (!req) {
return new HttpResponse(null, { status: 404 });
}
if (req.params.test_id === TEST_ID_1) {
return HttpResponse.json({
data: {
test1: "test1",
},
message: 'Test returned successfully',
status: 201,
});
}
if (req.params.test_id === TEST_ID_2) {
return HttpResponse.json({
data: {
test1: "test2",
},
message: 'Test returned successfully',
status: 201,
});
}
if (req.params.test_id === TEST_ID_3) {
return HttpResponse.json({
data: {
test1: "test3",
},
message: 'Test returned successfully',
status: 201,
});
}
return HttpResponse.json('other test id');
}),
];You can use above API as you wish(This is not this article's focus but you can use like below)
import axios from 'axios'
axios.get("/api/v1/tenants/test-id-1/tests")In this case, I defined this api like below.
http.get(`/api/v1/tenants/${TENANT_ID}/tests`, (req) => {
if (!req) {
return new HttpResponse(null, { status: 404 });
}
const mockResponse = {
data: [
{
test1: "test1"
},
{
test2: "test2"
},
{
test3: "test3"
},
],
message: 'Test returned successfully',
status: 200,
};
return HttpResponse.json(mockResponse);
}),So, the response is like below
{
data: [
{
test1: "test1"
},
{
test2: "test2"
},
{
test3: "test3"
},
],
message: 'Test returned successfully',
tatus: 200,
};Conclusion
Msw is an useful API mocking library which has good features. We are sometimes confused because there is a few source when we would like to solve specific issues such as with using Nuxt3…etc. I hope this article would help you.
Reference
msw: https://mswjs.io/
Thank you for reading!!