Setup Mock Service Worker Integration
Hey and welcome. In this guide I will show you how to setup the msw integration for exposition and include it into your application.
Confused? 😕
Feel free to reach out if something seems weird, confusing or unnecessary complex.
I'm willing to learn and welcome any kind of feedback with open arms. 🤗
Install dependencies
For this example you need to install the following dependencies:
pnpm add -D @exposition/{core,integrations} msw
yarn add -D @exposition/{core,integrations} msw
npm install -D @exposition/{core,integrations} msw
tl;dr setup ⚡
I'm like to fiddle around with code first, so a whole example to copy & paste is just nice.
Go ahead and grab the entire code from this cookbook and start building your mocks.
Example code 🍝
// #region imports
import { Exposition } from '@exposition/core'
import { createMswIntegration } from '@exposition/integrations/msw'
import { rest } from 'msw'
import { setupServer } from 'msw/node'
// #endregion imports
// ----------------------------------------------
// #region create-exposition
export const exampleExposition = new Exposition({
cart: {
options: ['filled', 'empty'],
},
} as const)
// #endregion create-exposition
// ----------------------------------------------
// #region setup-msw-integration
export const mswIntegration = createMswIntegration(
exampleExposition,
{
msw: setupServer(),
config: {
baseUrl: 'https://localhost:1337',
},
},
)
// #endregion setup-msw-integration
// ----------------------------------------------
// #region define-msw-handler
const cartItems = [
// ... define mocks for cart items
]
mswIntegration.createHandler((expositionValues) => {
return [
rest.get('/cart', (_request, response, context) => {
switch (expositionValues.cart) {
case 'filled':
return response(context.json({ items: cartItems }))
default:
return response(context.json({}))
}
}),
]
})
// #endregion define-msw-handler
// ----------------------------------------------
// #region init-exposition
exampleExposition.init()
// #endregion init-exposition
// #region define-msw-handler-with-config
mswIntegration.createHandler(
(_expositionValues, config) => {
return [
rest.get(`${config.baseUrl}/cart`, () => {
// ... your handler logic
}),
]
})
// #endregion define-msw-handler-with-config
Otherwise, if you wanna have a break down and a little bit of context follow the steps below.
Create Exposition
First create an Exposition
instance by passing in your configuration.
export const exampleExposition = new Exposition({
cart: {
options: ['filled', 'empty'],
},
} as const)
Next, use createMswIntegration
and add as a setting parameter ether setupClient
or setupServer
. In this case we use setupServer
.
export const mswIntegration = createMswIntegration(
exampleExposition,
{
msw: setupServer(),
config: {
baseUrl: 'https://localhost:1337',
},
},
)
Define handler
You can import the integration and add new handler by calling createHandler
. The spicy part is that the first parameter expositionValues
will automatically be fully typed. With that you can use a switch statement and your cases will be auto suggested. 🌶️
const cartItems = [
// ... define mocks for cart items
]
mswIntegration.createHandler((expositionValues) => {
return [
rest.get('/cart', (_request, response, context) => {
switch (expositionValues.cart) {
case 'filled':
return response(context.json({ items: cartItems }))
default:
return response(context.json({}))
}
}),
]
})
Pro gamer tip 👑
You can also use the very good @mswjs/data
library, in combination with @faker-js/faker
to build and fill your mocks. A cookbook for that will follow in the future.
Check out this playground example
import { factory, primaryKey } from '@mswjs/data'
import { faker } from '@faker-js/faker'
export const mockDatabase = factory({
items: {
id: primaryKey(faker.datatype.uuid),
name: () => faker.commerce.productName(),
quantity: () => faker.datatype.number({ min: 1, max: 20, precision: 2 }),
},
})
export function seedDatabase() {
Array.from(Array(5)).forEach(() => {
mockDatabase.items.create()
})
}
Dynamic config
Sometimes you want to create dynamic configs between multiple environments. An example. Your local environment has different endpoint than your staging environment. For that you can define a dynamic config and pass it to the integration and then use it while creating MSW interceptors.
export const mswIntegration = createMswIntegration(
exampleExposition,
{
msw: setupServer(),
config: {
baseUrl: 'https://localhost:1337',
},
},
)
This configuration can than be accessed as the second parameter of the handler function and used to define dynamic base paths or other creative ideas 💡.
mswIntegration.createHandler(
(_expositionValues, config) => {
return [
rest.get(`${config.baseUrl}/cart`, () => {
// ... your handler logic
}),
]
})
Finish 🏁
Initialize your exposition instance and test it in your app.
exampleExposition.init()
Next steps
Checkout the Vue-Devtools integration if you want to change settings in a conformable way.
Future 💫
I'm cooking new guides for the following topics:
vitest
— 🐍 Sneak peekjest
— 🌿 Similar to Vitest@mswjs/data
+@faker-js/faker
— ⏲️ TBD- Cypress — ⏲️ TBD
Other topics in my head:
- How to send links your colleagues — 🌐
@exposition/web
looking at you - SSR — 🚌 Sync between backend and frontend