Skip to main content

MSW Mocking

Mock Service Worker (MSW) intercepts network requests in the browser and returns mock responses. This lets you develop and test themes without a running backend or a real shop.

Activation

Start the dev server with VITE_USE_MSW=true:
VITE_USE_MSW=true VITE_SHOP_SLUG=demo bun run dev
The shop slug can be anything when using mocks — the mock handlers return the same data regardless of slug.

How It Works

When VITE_USE_MSW is true, the theme conditionally imports and starts the MSW service worker before rendering:
// main.tsx (simplified)
if (import.meta.env.VITE_USE_MSW === 'true') {
  const { worker } = await import('@/mocks/browser');
  await worker.start({ onUnhandledRequest: 'bypass' });
}
The onUnhandledRequest: 'bypass' setting means requests that do not match any handler (e.g. Vite HMR, static assets) pass through normally. The worker is set up in a separate file:
// mocks/browser.ts
import { setupWorker } from 'msw/browser';
import { handlers } from './handlers';

export const worker = setupWorker(...handlers);
MSW requires a service worker file (mockServiceWorker.js) in your public/ directory. The reference theme already includes this file. If you are creating a new theme, generate it with bunx msw init public/.

Mocked Endpoints

The following API endpoints are intercepted by the mock handlers:
EndpointMethodResponse
*/v1/storefront/shops/name/:storeSlugGETMock shop object ({ status: 200, data: { shop: mockShop } })
*/v1/storefront/shops/domain/:domainGETMock shop object ({ status: 200, data: { shop: mockShop } })
*/v1/storefront/products/public/:storeSlugGETArray of mock products ({ status: 200, data: { products: mockProducts } })
*/v1/storefront/products/unique/:idGETSingle product by ID or slug. Returns 404 if not found.
*/v1/storefront/coupons/checkPOSTCoupon validation. Codes SAVE10 and FLORAIN return a valid 10% discount. Other codes return invalid.

Wildcard Matching

Handlers use the '*/v1/...' URL pattern. The leading * matches any protocol and host, so mocks work regardless of your VITE_API_BASE_URL setting — whether it points to localhost, https://api.shoppex.io, or anything else.

What Is Not Mocked

The following SDK features hit the real API and are not covered by the default mock handlers:
FeatureSDK MethodEndpoint
Checkoutcheckout()POST /v1/storefront/invoices/from-cart
Theme SettingsfetchPublishedThemeSettings()GET /v1/storefront/themes/builder/published/:shopSlug
InvoicesgetInvoice(), getInvoiceStatus()GET /v1/storefront/invoices/unique/:invoiceId
GET /v1/storefront/invoices/status/:invoiceId
PagesgetPages(), getPage()GET /v1/storefront/shops/name/:storeSlug/pages
GET /v1/storefront/shops/name/:storeSlug/pages/:slug
NavigationgetMenus(), getMenu()GET /v1/storefront/shops/name/:storeSlug/menus
GET /v1/storefront/shops/name/:storeSlug/menus/:title
AnalyticstrackPageView()POST /v1/storefront/shops/:storeSlug/ping
If you need to mock additional endpoints, add handlers to mocks/handlers.ts:
import { http, HttpResponse } from 'msw';

// Example: mock the pages endpoint
http.get('*/v1/storefront/shops/name/:storeSlug/pages', () => {
  return HttpResponse.json({
    status: 200,
    data: {
      pages: [
        // Minimal example: include additional fields if your UI relies on them.
        {
          id: 'page_1',
          slug: 'about',
          name: 'About Us',
          content: '<p>Hello</p>',
          template_type: 'custom',
          is_system: false,
          settings: null,
          visible_after: null,
          created_at: Date.now(),
          updated_at: Date.now(),
        },
      ],
    },
  });
});

MSW vs Public API

MSW MocksPublic API
Requires backendNoNo (uses api.shoppex.io)
DataStatic mock dataReal shop data
SpeedInstant (no network)Network latency
Coverage5 endpoints (see above)All endpoints
Best forUI development, prototypingIntegration testing, final QA
Env varVITE_USE_MSW=trueVITE_API_BASE_URL=https://api.shoppex.io

Next Steps