@dbs-portal/tool-mock
Version:
API mocking toolkit using MSW for DBS Portal development workflows
333 lines • 9.74 kB
JavaScript
/**
* Zustand integration for mock state management
*/
import { isMswSetup } from '../core/setup';
/**
* Create mock-aware Zustand store
*/
export function createMockStore(config) {
const { name, initialState, mockData, actions = {}, persist = false, storageKey } = config;
// Merge initial state with mock data if mocking is enabled
const finalInitialState = isMswSetup() && mockData
? { ...initialState, ...mockData }
: initialState;
// Create store implementation (simplified)
let state = { ...finalInitialState };
const listeners = new Set();
const store = {
getState: () => state,
setState: (partial) => {
const nextState = typeof partial === 'function' ? partial(state) : partial;
state = { ...state, ...nextState };
// Notify listeners
listeners.forEach(listener => listener());
// Persist if enabled
if (persist && storageKey) {
try {
localStorage.setItem(storageKey, JSON.stringify(state));
}
catch (error) {
console.warn(`Failed to persist store ${name}:`, error);
}
}
},
subscribe: (listener) => {
listeners.add(listener);
return () => listeners.delete(listener);
},
destroy: () => {
listeners.clear();
if (persist && storageKey) {
try {
localStorage.removeItem(storageKey);
}
catch (error) {
console.warn(`Failed to clear persisted store ${name}:`, error);
}
}
},
// Add mock actions
...Object.entries(actions).reduce((acc, [actionName, actionFn]) => {
acc[actionName] = (...args) => {
const result = actionFn(...args);
// If action returns state update, apply it
if (result && typeof result === 'object') {
store.setState(result);
}
return result;
};
return acc;
}, {}),
};
// Load persisted state if available
if (persist && storageKey) {
try {
const persisted = localStorage.getItem(storageKey);
if (persisted) {
const persistedState = JSON.parse(persisted);
state = { ...state, ...persistedState };
}
}
catch (error) {
console.warn(`Failed to load persisted store ${name}:`, error);
}
}
return store;
}
/**
* Mock store manager
*/
export class MockStoreManager {
stores = new Map();
// private _config: ZustandIntegrationConfig // Unused for now
constructor(_config = {}) {
// this._config = config // Unused for now
}
/**
* Register a mock store
*/
registerStore(name, storeConfig) {
const store = createMockStore({ ...storeConfig, name });
this.stores.set(name, store);
return store;
}
/**
* Get registered store
*/
getStore(name) {
return this.stores.get(name);
}
/**
* Update store state
*/
updateStore(name, update) {
const store = this.stores.get(name);
if (store) {
store.setState(update);
}
}
/**
* Reset store to initial state
*/
resetStore(name) {
const store = this.stores.get(name);
if (store && store.reset) {
store.reset();
}
}
/**
* Clear all stores
*/
clearAllStores() {
this.stores.forEach(store => {
if (store.destroy) {
store.destroy();
}
});
this.stores.clear();
}
/**
* Get all store names
*/
getStoreNames() {
return Array.from(this.stores.keys());
}
/**
* Apply global mock state
*/
applyGlobalMockState(globalState) {
if (!isMswSetup())
return;
Object.entries(globalState).forEach(([storeName, stateUpdate]) => {
this.updateStore(storeName, stateUpdate);
});
}
}
/**
* Create mock store hooks for React
*/
export function createMockStoreHooks(store) {
return {
/**
* Use store hook
*/
useStore: (selector) => {
// Simplified implementation - in real scenario would use React hooks
const state = store.getState();
return selector ? selector(state) : state;
},
/**
* Use store actions
*/
useStoreActions: () => {
return Object.keys(store)
.filter(key => typeof store[key] === 'function' && key !== 'getState' && key !== 'setState' && key !== 'subscribe')
.reduce((actions, actionName) => {
actions[actionName] = store[actionName];
return actions;
}, {});
},
};
}
/**
* Mock data providers for common store patterns
*/
export const mockStoreProviders = {
/**
* User store mock data
*/
userStore: {
initialState: {
currentUser: null,
isAuthenticated: false,
loading: false,
error: null,
},
mockData: {
currentUser: {
id: '1',
email: 'user@example.com',
firstName: 'Mock',
lastName: 'User',
roles: ['user'],
},
isAuthenticated: true,
},
actions: {
login: (credentials) => ({
currentUser: {
id: '1',
email: credentials.email,
firstName: 'Mock',
lastName: 'User',
},
isAuthenticated: true,
loading: false,
error: null,
}),
logout: () => ({
currentUser: null,
isAuthenticated: false,
loading: false,
error: null,
}),
},
},
/**
* UI store mock data
*/
uiStore: {
initialState: {
sidebarOpen: true,
theme: 'light',
notifications: [],
loading: false,
},
mockData: {
notifications: [
{
id: '1',
type: 'info',
message: 'Mock notification',
timestamp: new Date().toISOString(),
},
],
},
actions: {
toggleSidebar: () => (state) => ({
sidebarOpen: !state.sidebarOpen,
}),
setTheme: (theme) => ({ theme }),
addNotification: (notification) => (state) => ({
notifications: [...state.notifications, notification],
}),
},
},
/**
* Data store mock data
*/
dataStore: {
initialState: {
items: [],
loading: false,
error: null,
pagination: {
page: 1,
pageSize: 10,
total: 0,
},
},
mockData: {
items: Array.from({ length: 5 }, (_, i) => ({
id: `item-${i + 1}`,
name: `Mock Item ${i + 1}`,
description: `Description for mock item ${i + 1}`,
createdAt: new Date().toISOString(),
})),
pagination: {
page: 1,
pageSize: 10,
total: 5,
},
},
actions: {
setItems: (items) => ({ items }),
addItem: (item) => (state) => ({
items: [...state.items, item],
}),
removeItem: (id) => (state) => ({
items: state.items.filter((item) => item.id !== id),
}),
setLoading: (loading) => ({ loading }),
setError: (error) => ({ error }),
},
},
};
/**
* Setup mock stores for development
*/
export function setupMockStores(storeConfigs = {}) {
const manager = new MockStoreManager();
// Register provided store configs
Object.entries(storeConfigs).forEach(([name, config]) => {
manager.registerStore(name, config);
});
// Register default mock stores if none provided
if (Object.keys(storeConfigs).length === 0) {
Object.entries(mockStoreProviders).forEach(([name, config]) => {
manager.registerStore(name, { ...config, name });
});
}
return manager;
}
/**
* Integration with existing Zustand stores
*/
export function integrateMockWithZustand(existingStore, mockData, options = {}) {
if (!isMswSetup()) {
return existingStore;
}
const { override = false, merge = true } = options;
if (override) {
// Replace store state entirely
existingStore.setState(mockData);
}
else if (merge) {
// Merge mock data with existing state
const currentState = existingStore.getState();
existingStore.setState({ ...currentState, ...mockData });
}
return existingStore;
}
/**
* Mock store devtools integration
*/
export function setupMockStoreDevtools(stores) {
if (typeof window !== 'undefined' && isMswSetup()) {
// Add mock store information to window for debugging
;
window.__MOCK_STORES__ = stores;
console.log('Mock stores available:', Object.keys(stores));
}
}
//# sourceMappingURL=zustand.js.map