@arsams/mockkit
v0.0.1
Published
Framework-agnostic toolkit for MSW mocking.
Maintainers
Readme
@arsams/mockkit
Framework-agnostic toolkit for API mocking with MSW. Provides a centralized, controllable mocking system that works in any JavaScript/TypeScript environment.
For React integrations (hooks and control panel components), see @arsams/mockkit-react.
Features
- Framework-agnostic core - Works in browser, Node.js, or any JS/TS environment
- Centralized configuration - Single source of truth for all mocking behavior
- Response variants - Support for success, error, empty, slow, and offline modes
- Scenarios - Group multiple route configurations together
- Tree-shakeable - Import only what you need
- Type-safe - Full TypeScript support
- Zero dependencies (except MSW) - Minimal bundle size
Installation
pnpm install @arsams/mockkit mswFor React support, install the separate React package:
pnpm install @arsams/mockkit-react @arsams/mockkit msw react react-domQuick Start
Important: This library does not provide default handlers, scenarios, or stream sequences. You must create and register your own before using the library.
1. Create Handlers
// src/mocks/handlers.ts
import { buildRestHandler } from "@arsams/mockkit";
import { HttpResponse } from "msw";
export const fetchWeatherHandler = buildRestHandler({
id: "weather.fetch",
method: "get",
path: "/api/weather",
label: "Fetch Weather",
variants: {
success: () =>
HttpResponse.json({
location: "San Francisco, CA",
temperature: 22,
condition: "sunny",
humidity: 65,
windSpeed: 15,
}),
error: () =>
HttpResponse.json(
{ error: "Failed to fetch weather data" },
{ status: 500 },
),
empty: () => HttpResponse.json({}),
},
});
export const handlers = [fetchWeatherHandler];Note: You must export your handlers array and import it in your setup files (see steps 2 and 3 below).
2. Register Scenarios and Stream Sequences (Optional)
// src/mocks/scenarios.ts
import { addScenario } from "@arsams/mockkit";
// Register scenarios before initializing the worker/server
addScenario("success", {
title: "All Success",
routes: {
"weather.fetch": { mode: "success" },
},
});
addScenario("errorState", {
title: "All Errors",
routes: {
"weather.fetch": { mode: "error" },
},
});// src/mocks/streamSequences.ts
import { addStreamSequence } from "@arsams/mockkit";
import { createMockEvent } from "@arsams/mockkit";
// Register stream sequences before initializing the worker/server
addStreamSequence("weatherCurrentConditions", {
title: "Current Weather Conditions",
events: [
{
event: createMockEvent("weather_CurrentConditions", {
RunStatus: 0,
resultJson: JSON.stringify({
temperature: 22,
condition: "sunny",
location: "San Francisco, CA",
}),
}),
},
],
});3. Browser Setup
// src/mocks/browser.ts
import { startMockWorker } from "@arsams/mockkit/browser";
import { handlers } from "./handlers";
// Import your scenarios and stream sequences to register them
import "./scenarios";
import "./streamSequences";
export async function initMocks() {
if (import.meta.env.DEV) {
await startMockWorker({
handlers,
// Optional: apply a scenario you've registered
initialScenario: "success",
quiet: false,
});
}
}// main.tsx
import { initMocks } from "./mocks/browser";
initMocks().then(() => {
ReactDOM.createRoot(document.getElementById("root")!).render(<App />);
});4. Node/Test Setup
// vitest.setup.ts or jest.setup.ts
import { setupMockServer } from "@arsams/mockkit/node";
import { handlers } from "./mocks/handlers";
// Import your scenarios and stream sequences to register them
import "./mocks/scenarios";
import "./mocks/streamSequences";
const server = setupMockServer({
handlers,
// Optional: apply a scenario you've registered
initialScenario: "success",
});
beforeAll(() => server.listen({ onUnhandledRequest: "bypass" }));
afterEach(() => server.resetHandlers());
afterAll(() => server.close());5. Use in Your App
// Framework-agnostic usage
import { $mockConfigState, setRouteMode } from "@arsams/mockkit";
// Get current state
const state = $mockConfigState.get();
console.log(state.enabled); // true
// Change response mode
setRouteMode("weather.fetch", "error");
// Subscribe to changes
import { onMount } from "nanostores";
const unsubscribe = onMount($mockConfigState, () => {
console.log("Store updated:", $mockConfigState.get());
});6. React Integration (Optional)
If you're using React, install and use @arsams/mockkit-react:
// Install: pnpm install @arsams/mockkit-react
import { useStore, MSWControlPanel } from "@arsams/mockkit-react";
function App() {
const enabled = useStore((state) => state.enabled);
return (
<>
<YourApp />
{import.meta.env.DEV && <MSWControlPanel />}
</>
);
}See the @arsams/mockkit-react documentation for more details.
Core Concepts
Response Modes
Each handler can respond in multiple modes:
success- Happy-path response with realistic dataerror- Error response (4xx/5xx)empty- Success response with no dataslow- Delayed response for testing loading statesoffline- Simulated network failure
Scenarios
Scenarios group multiple route configurations together:
import { addScenario } from "@arsams/mockkit";
addScenario("errorState", {
title: "All Errors",
routes: {
"weather.fetch": { mode: "error" },
"weather.forecast": { mode: "error" },
},
});
// Apply scenario
import { setScenario } from "@arsams/mockkit";
setScenario("errorState");Route Configuration
Routes are automatically registered when handlers are accessed. You can configure them programmatically:
import { setRouteConfig, enableRoute, disableRoute } from "@arsams/mockkit";
// Configure a route
setRouteConfig("weather.fetch", {
enabled: true,
mode: "error",
label: "Fetch Weather",
});
// Enable/disable routes
enableRoute("weather.fetch");
disableRoute("weather.forecast");API Reference
Core Exports (@arsams/mockkit)
Store and State Management
$mockConfigState- Framework-agnostic store instance (nanostores atom)$scenarios- Store containing all registered scenarios$currentScenario- Store containing the currently active scenario name (or null)$streamEventSequences- Store containing all registered stream sequences$activeStream- Store containing the currently active stream sequence name (or null)
Store Actions
setGlobalEnabled(enabled: boolean)- Enable/disable all mockingsetLogRequests(enabled: boolean)- Enable/disable request loggingsetRouteMode(routeId: string, mode: ResponseMode)- Set response mode for a routeenableRoute(routeId: string)- Enable a specific routedisableRoute(routeId: string)- Disable a specific routesetRouteConfig(routeId: string, config: Partial<RouteConfig>)- Configure a routegetRouteMode(routeId: string)- Get the current response mode for a routeisRouteEnabled(routeId: string)- Check if a route is enabledgetRouteConfig(routeId: string)- Get the full configuration for a route
Scenario Management
addScenario(name: string, config: ScenarioConfig)- Register a scenario (must be called beforestartMockWorkerorsetupMockServer)getScenario(name: string)- Get a scenario by namegetAllScenarios()- Get all registered scenariossetScenario(name: string)- Apply a registered scenarioclearScenario()- Clear the current scenario
Stream Sequence Management
addStreamSequence(name: string, config: StreamEventSequence)- Register a stream sequence (must be called beforestartMockWorkerorsetupMockServer)getStreamSequence(name: string)- Get a stream sequence by namegetAllStreamSequences()- Get all registered stream sequencessetActiveStreamSequence(name: string | null)- Set the active stream sequenceclearActiveStreamSequence()- Clear the active stream sequence
Handler Builders
buildRestHandler(config: RestHandlerConfig)- Build an MSW REST handler
Utilities
logger- Logger instance for logging (respectslogRequestssetting)print- Convenience logger methods (info, warn, error, system.*)createUnhandledRequestWarning- Function for handling unhandled MSW requestscreateMockEvent,createStreamEvent,createWeatherCurrentConditionsEvent, etc. - Stream event creation utilities
Types
ResponseMode- Type for response modes: "success" | "error" | "empty" | "slow" | "offline"RouteConfig- Type for route configurationScenarioConfig- Type for scenario configurationStreamEventSequence- Type for stream event sequence configurationMockConfigState- Type for the mock config store state
Browser Exports (@arsams/mockkit/browser)
startMockWorker(options: StartMockWorkerOptions)- Start MSW worker in browseroptions.handlers- Array of MSW handlers (required)options.initialScenario?- Initial scenario to apply (optional)options.quiet?- Suppress MSW startup messages (optional, default: false)
Node Exports (@arsams/mockkit/node)
setupMockServer(options: SetupMockServerOptions)- Setup MSW server for Node/testingoptions.handlers- Array of MSW handlers (required)options.initialScenario?- Initial scenario to apply (optional)
Examples
Complete Example
Here's a complete example showing how to set up handlers, scenarios, and stream sequences:
// src/mocks/handlers.ts
import { buildRestHandler } from "@arsams/mockkit";
import { HttpResponse } from "msw";
export const fetchWeatherHandler = buildRestHandler({
id: "weather.fetch",
method: "get",
path: "/api/weather",
variants: {
success: () =>
HttpResponse.json({
location: "San Francisco, CA",
temperature: 22,
condition: "sunny",
}),
error: () =>
HttpResponse.json({ error: "Failed to fetch weather" }, { status: 500 }),
},
});
export const handlers = [fetchWeatherHandler];// src/mocks/scenarios.ts
import { addScenario } from "@arsams/mockkit";
addScenario("success", {
title: "All Success",
routes: {
"weather.fetch": { mode: "success" },
},
});
addScenario("errorState", {
title: "All Errors",
routes: {
"weather.fetch": { mode: "error" },
},
});// src/mocks/streamSequences.ts
import { addStreamSequence } from "@arsams/mockkit";
import { createMockEvent } from "@arsams/mockkit";
addStreamSequence("weatherCurrentConditions", {
title: "Current Weather Conditions",
events: [
{
event: createMockEvent("weather_CurrentConditions", {
RunStatus: 0,
resultJson: JSON.stringify({
location: "San Francisco, CA",
temperature: 22,
condition: "sunny",
}),
}),
},
],
});// src/mocks/browser.ts
import { startMockWorker } from "@arsams/mockkit/browser";
import { handlers } from "./handlers";
import "./scenarios";
import "./streamSequences";
export async function initMocks() {
if (import.meta.env.DEV) {
await startMockWorker({
handlers,
initialScenario: "success",
});
}
}Framework-Agnostic Design
The core functionality is completely framework-agnostic:
- Store - Vanilla JavaScript event emitter, no React dependencies
- Builders - Work with any framework
- Types - Pure TypeScript, no framework assumptions
For React support, use the separate @arsams/mockkit-react package. The core package is framework-agnostic and can be used in Vue, Svelte, Angular, or plain JavaScript.
License
MIT
Contributing
See CONTRIBUTING.md for guidelines.
